diff options
Diffstat (limited to 'decode_scan.go')
-rw-r--r-- | decode_scan.go | 62 |
1 files changed, 42 insertions, 20 deletions
diff --git a/decode_scan.go b/decode_scan.go index fee9ec6..9fa6181 100644 --- a/decode_scan.go +++ b/decode_scan.go @@ -11,13 +11,11 @@ import ( type runeTypeScanner interface { // The returned error is a *ReadError, a *SyntaxError, or nil. - // An EOF condition is represented either as + // An EOF condition is represented as one of: // - // (char, size, RuneTypeEOF, nil) - // - // or - // - // (char, size, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.ErrUnexepctedEOF}) + // end of value but not file: (_, >0, RuneTypeEOF, nil) + // end of both value and file: (_, 0, RuneTypeEOF, nil) + // end of file but not value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.ErrUnexepctedEOF}) ReadRuneType() (rune, int, RuneType, error) // The returned error is a *DecodeReadError, a *DecodeSyntaxError, io.EOF, or nil. ReadRune() (rune, int, error) @@ -31,6 +29,8 @@ type runeTypeScanner interface { type runeTypeScannerImpl struct { inner io.RuneReader + initialized bool + parser Parser offset int64 @@ -109,6 +109,7 @@ func (sc *runeTypeScannerImpl) ReadRuneType() (rune, int, RuneType, error) { } } } + sc.initialized = true sc.repeat = false sc.stuck = sc.rType == RuneTypeEOF || sc.rType == RuneTypeError return sc.rRune, sc.rSize, sc.rType, sc.rErr @@ -128,12 +129,13 @@ func (sc *runeTypeScannerImpl) ReadRune() (rune, int, error) { var ErrInvalidUnreadRune = errors.New("lowmemjson: invalid use of UnreadRune") -// UnreadRune undoes a call to .ReadRune() or .ReadRuneType(). If the -// last call to .ReadRune() or .ReadRuneType() has already been -// unread, or if that call returned an error or RuneTypeEOF, then -// ErrInvalidRune is returned. Otherwise, nil is returned. +// UnreadRune undoes a call to .ReadRune() or .ReadRuneType(). +// +// If the last call to .ReadRune() or .ReadRuneType() has already been +// unread, or if that call returned a rune with size 0, then +// ErrInvalidUnreadRune is returned. Otherwise, nil is returned. func (sc *runeTypeScannerImpl) UnreadRune() error { - if sc.stuck || sc.repeat { + if !sc.initialized || sc.repeat || sc.rSize == 0 { return ErrInvalidUnreadRune } sc.repeat = true @@ -191,27 +193,46 @@ type elemRuneTypeScanner struct { parser Parser repeat bool + stuck bool rType RuneType + rErr error } var _ runeTypeScanner = (*elemRuneTypeScanner)(nil) func (sc *elemRuneTypeScanner) ReadRuneType() (rune, int, RuneType, error) { + // Read it, run it through the parent's parser. r, s, t, e := sc.inner.ReadRuneType() - // Check if we need to insert a premature EOF - if t != RuneTypeError && t != RuneTypeEOF { - if sc.repeat { + // Run it through our child parser. + if s > 0 || errors.Is(e, io.ErrUnexpectedEOF) { + if sc.repeat || sc.stuck { sc.repeat = false } else { - sc.rType, _ = sc.parser.HandleRune(r) - } - if sc.rType == RuneTypeEOF { - _ = sc.inner.UnreadRune() + var err error + if s > 0 { + sc.rType, err = sc.parser.HandleRune(r) + } else { + sc.rType, err = sc.parser.HandleEOF() + } + if err != nil { + sc.rErr = &DecodeSyntaxError{ + Offset: sc.inner.InputOffset(), + Err: err, + } + } else { + sc.rErr = nil + } } - t = sc.rType + sc.stuck = sc.rType == RuneTypeEOF || sc.rType == RuneTypeError + t, e = sc.rType, sc.rErr } + + // Check if we need to truncate the result. if t == RuneTypeEOF { + if s > 0 { + _ = sc.inner.UnreadRune() + } return 0, 0, RuneTypeEOF, nil } @@ -231,8 +252,9 @@ func (sc *elemRuneTypeScanner) ReadRune() (rune, int, error) { } func (sc *elemRuneTypeScanner) UnreadRune() error { + ret := sc.inner.UnreadRune() sc.repeat = true - return sc.inner.UnreadRune() + return ret } func (sc *elemRuneTypeScanner) InputOffset() int64 { return sc.inner.InputOffset() } |