// A Decoder reads and decodes JSON values from an input stream.
type Decoder struct {
- r io.Reader
- buf []byte
- d decodeState
- scanp int // start of unread data in buf
- scan scanner
- err error
+ r io.Reader
+ buf []byte
+ d decodeState
+ scanp int // start of unread data in buf
+ scanned int64 // amount of data already scanned
+ scan scanner
+ err error
tokenState int
tokenStack []int
}
if !dec.tokenValueAllowed() {
- return &SyntaxError{msg: "not at beginning of value"}
+ return &SyntaxError{msg: "not at beginning of value", Offset: dec.offset()}
}
// Read whole value into buffer.
// Make room to read more into the buffer.
// First slide down data already consumed.
if dec.scanp > 0 {
+ dec.scanned += int64(dec.scanp)
n := copy(dec.buf, dec.buf[dec.scanp:])
dec.buf = dec.buf[:n]
dec.scanp = 0
return err
}
if c != ',' {
- return &SyntaxError{"expected comma after array element", 0}
+ return &SyntaxError{"expected comma after array element", dec.offset()}
}
dec.scanp++
dec.tokenState = tokenArrayValue
return err
}
if c != ':' {
- return &SyntaxError{"expected colon after object key", 0}
+ return &SyntaxError{"expected colon after object key", dec.offset()}
}
dec.scanp++
dec.tokenState = tokenObjectValue
err := dec.Decode(&x)
dec.tokenState = old
if err != nil {
- clearOffset(err)
return nil, err
}
dec.tokenState = tokenObjectColon
}
var x interface{}
if err := dec.Decode(&x); err != nil {
- clearOffset(err)
return nil, err
}
return x, nil
}
}
-func clearOffset(err error) {
- if s, ok := err.(*SyntaxError); ok {
- s.Offset = 0
- }
-}
-
func (dec *Decoder) tokenError(c byte) (Token, error) {
var context string
switch dec.tokenState {
case tokenObjectComma:
context = " after object key:value pair"
}
- return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, 0}
+ return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, dec.offset()}
}
// More reports whether there is another element in the
err = dec.refill()
}
}
+
+func (dec *Decoder) offset() int64 {
+ return dec.scanned + int64(dec.scanp)
+}
{json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{
Delim('['),
decodeThis{map[string]interface{}{"a": float64(1)}},
- decodeThis{&SyntaxError{"expected comma after array element", 0}},
+ decodeThis{&SyntaxError{"expected comma after array element", 11}},
}},
- {json: `{ "a" 1 }`, expTokens: []interface{}{
- Delim('{'), "a",
- decodeThis{&SyntaxError{"expected colon after object key", 0}},
+ {json: `{ "` + strings.Repeat("a", 513) + `" 1 }`, expTokens: []interface{}{
+ Delim('{'), strings.Repeat("a", 513),
+ decodeThis{&SyntaxError{"expected colon after object key", 518}},
+ }},
+ {json: `{ "\a" }`, expTokens: []interface{}{
+ Delim('{'),
+ &SyntaxError{"invalid character 'a' in string escape code", 3},
+ }},
+ {json: ` \a`, expTokens: []interface{}{
+ &SyntaxError{"invalid character '\\\\' looking for beginning of value", 1},
}},
}
tk, err = dec.Token()
}
if experr, ok := etk.(error); ok {
- if err == nil || err.Error() != experr.Error() {
- t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err)
+ if err == nil || !reflect.DeepEqual(err, experr) {
+ t.Errorf("case %v: Expected error %#v in %q, but was %#v", ci, experr, tcase.json, err)
}
break
} else if err == io.EOF {
t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json)
break
} else if err != nil {
- t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json)
+ t.Errorf("case %v: Unexpected error '%#v' in %q", ci, err, tcase.json)
break
}
if !reflect.DeepEqual(tk, etk) {