mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
json: keep track of error offset in SyntaxError
R=rsc CC=golang-dev https://golang.org/cl/4430043
This commit is contained in:
parent
e806565626
commit
9b8d4e0977
3 changed files with 17 additions and 10 deletions
|
|
@ -71,7 +71,7 @@ var unmarshalTests = []unmarshalTest{
|
||||||
{`{"X":"a", "y":"b", "Z":"c"}`, new(badTag), badTag{"a", "b", "c"}, nil},
|
{`{"X":"a", "y":"b", "Z":"c"}`, new(badTag), badTag{"a", "b", "c"}, nil},
|
||||||
|
|
||||||
// syntax errors
|
// syntax errors
|
||||||
{`{"X": "foo", "Y"}`, nil, nil, SyntaxError("invalid character '}' after object key")},
|
{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
|
||||||
|
|
||||||
// composite tests
|
// composite tests
|
||||||
{allValueIndent, new(All), allValue, nil},
|
{allValueIndent, new(All), allValue, nil},
|
||||||
|
|
@ -125,12 +125,12 @@ func TestMarshalBadUTF8(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshal(t *testing.T) {
|
func TestUnmarshal(t *testing.T) {
|
||||||
var scan scanner
|
|
||||||
for i, tt := range unmarshalTests {
|
for i, tt := range unmarshalTests {
|
||||||
|
var scan scanner
|
||||||
in := []byte(tt.in)
|
in := []byte(tt.in)
|
||||||
if err := checkValid(in, &scan); err != nil {
|
if err := checkValid(in, &scan); err != nil {
|
||||||
if !reflect.DeepEqual(err, tt.err) {
|
if !reflect.DeepEqual(err, tt.err) {
|
||||||
t.Errorf("#%d: checkValid: %v", i, err)
|
t.Errorf("#%d: checkValid: %#v", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
func checkValid(data []byte, scan *scanner) os.Error {
|
func checkValid(data []byte, scan *scanner) os.Error {
|
||||||
scan.reset()
|
scan.reset()
|
||||||
for _, c := range data {
|
for _, c := range data {
|
||||||
|
scan.bytes++
|
||||||
if scan.step(scan, int(c)) == scanError {
|
if scan.step(scan, int(c)) == scanError {
|
||||||
return scan.err
|
return scan.err
|
||||||
}
|
}
|
||||||
|
|
@ -56,10 +57,12 @@ func nextValue(data []byte, scan *scanner) (value, rest []byte, err os.Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A SyntaxError is a description of a JSON syntax error.
|
// A SyntaxError is a description of a JSON syntax error.
|
||||||
type SyntaxError string
|
type SyntaxError struct {
|
||||||
|
msg string // description of error
|
||||||
func (e SyntaxError) String() string { return string(e) }
|
Offset int64 // error occurred after reading Offset bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SyntaxError) String() string { return e.msg }
|
||||||
|
|
||||||
// A scanner is a JSON scanning state machine.
|
// A scanner is a JSON scanning state machine.
|
||||||
// Callers call scan.reset() and then pass bytes in one at a time
|
// Callers call scan.reset() and then pass bytes in one at a time
|
||||||
|
|
@ -89,6 +92,9 @@ type scanner struct {
|
||||||
// 1-byte redo (see undo method)
|
// 1-byte redo (see undo method)
|
||||||
redoCode int
|
redoCode int
|
||||||
redoState func(*scanner, int) int
|
redoState func(*scanner, int) int
|
||||||
|
|
||||||
|
// total bytes consumed, updated by decoder.Decode
|
||||||
|
bytes int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// These values are returned by the state transition functions
|
// These values are returned by the state transition functions
|
||||||
|
|
@ -148,7 +154,7 @@ func (s *scanner) eof() int {
|
||||||
return scanEnd
|
return scanEnd
|
||||||
}
|
}
|
||||||
if s.err == nil {
|
if s.err == nil {
|
||||||
s.err = SyntaxError("unexpected end of JSON input")
|
s.err = &SyntaxError{"unexpected end of JSON input", s.bytes}
|
||||||
}
|
}
|
||||||
return scanError
|
return scanError
|
||||||
}
|
}
|
||||||
|
|
@ -581,7 +587,7 @@ func stateError(s *scanner, c int) int {
|
||||||
// error records an error and switches to the error state.
|
// error records an error and switches to the error state.
|
||||||
func (s *scanner) error(c int, context string) int {
|
func (s *scanner) error(c int, context string) int {
|
||||||
s.step = stateError
|
s.step = stateError
|
||||||
s.err = SyntaxError("invalid character " + quoteChar(c) + " " + context)
|
s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes}
|
||||||
return scanError
|
return scanError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ func NewDecoder(r io.Reader) *Decoder {
|
||||||
return &Decoder{r: r}
|
return &Decoder{r: r}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode reads the next JSON-encoded value from the
|
// Decode reads the next JSON-encoded value from its
|
||||||
// connection and stores it in the value pointed to by v.
|
// input and stores it in the value pointed to by v.
|
||||||
//
|
//
|
||||||
// See the documentation for Unmarshal for details about
|
// See the documentation for Unmarshal for details about
|
||||||
// the conversion of JSON into a Go value.
|
// the conversion of JSON into a Go value.
|
||||||
|
|
@ -62,6 +62,7 @@ Input:
|
||||||
for {
|
for {
|
||||||
// Look in the buffer for a new value.
|
// Look in the buffer for a new value.
|
||||||
for i, c := range dec.buf[scanp:] {
|
for i, c := range dec.buf[scanp:] {
|
||||||
|
dec.scan.bytes++
|
||||||
v := dec.scan.step(&dec.scan, int(c))
|
v := dec.scan.step(&dec.scan, int(c))
|
||||||
if v == scanEnd {
|
if v == scanEnd {
|
||||||
scanp += i
|
scanp += i
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue