{`{"X":"a", "y":"b", "Z":"c"}`, new(badTag), badTag{"a", "b", "c"}, nil},
// 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
{allValueIndent, new(All), allValue, nil},
}
func TestUnmarshal(t *testing.T) {
- var scan scanner
for i, tt := range unmarshalTests {
+ var scan scanner
in := []byte(tt.in)
if err := checkValid(in, &scan); err != nil {
if !reflect.DeepEqual(err, tt.err) {
- t.Errorf("#%d: checkValid: %v", i, err)
+ t.Errorf("#%d: checkValid: %#v", i, err)
continue
}
}
func checkValid(data []byte, scan *scanner) os.Error {
scan.reset()
for _, c := range data {
+ scan.bytes++
if scan.step(scan, int(c)) == scanError {
return scan.err
}
}
// A SyntaxError is a description of a JSON syntax error.
-type SyntaxError string
-
-func (e SyntaxError) String() string { return string(e) }
+type SyntaxError struct {
+ msg string // description of error
+ Offset int64 // error occurred after reading Offset bytes
+}
+func (e *SyntaxError) String() string { return e.msg }
// A scanner is a JSON scanning state machine.
// Callers call scan.reset() and then pass bytes in one at a time
// 1-byte redo (see undo method)
redoCode int
redoState func(*scanner, int) int
+
+ // total bytes consumed, updated by decoder.Decode
+ bytes int64
}
// These values are returned by the state transition functions
return scanEnd
}
if s.err == nil {
- s.err = SyntaxError("unexpected end of JSON input")
+ s.err = &SyntaxError{"unexpected end of JSON input", s.bytes}
}
return scanError
}
// error records an error and switches to the error state.
func (s *scanner) error(c int, context string) int {
s.step = stateError
- s.err = SyntaxError("invalid character " + quoteChar(c) + " " + context)
+ s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes}
return scanError
}
return &Decoder{r: r}
}
-// Decode reads the next JSON-encoded value from the
-// connection and stores it in the value pointed to by v.
+// Decode reads the next JSON-encoded value from its
+// input and stores it in the value pointed to by v.
//
// See the documentation for Unmarshal for details about
// the conversion of JSON into a Go value.
for {
// Look in the buffer for a new value.
for i, c := range dec.buf[scanp:] {
+ dec.scan.bytes++
v := dec.scan.step(&dec.scan, int(c))
if v == scanEnd {
scanp += i