diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2023-01-29 20:59:37 -0700 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2023-01-30 22:56:40 -0700 |
commit | b3f4186f2b8e992f56f898784b1cd28bfd7550ca (patch) | |
tree | 9c9f0086c386a63a12b622945248916d51c480a5 /decode_scan.go | |
parent | bc1bacc410ddfa444c5bf0e56f33a7da440658ae (diff) |
Invent "barriers" instead of nesting parsers
Diffstat (limited to 'decode_scan.go')
-rw-r--r-- | decode_scan.go | 143 |
1 files changed, 39 insertions, 104 deletions
diff --git a/decode_scan.go b/decode_scan.go index 261aaa6..e233caf 100644 --- a/decode_scan.go +++ b/decode_scan.go @@ -5,31 +5,12 @@ package lowmemjson import ( - "errors" "io" "git.lukeshu.com/go/lowmemjson/internal" ) -type runeTypeScanner interface { - // The returned error is a *ReadError, a *SyntaxError, or nil. - // An EOF condition is represented as one of: - // - // end of value but not file: (_, >0, RuneTypeEOF, nil) - // end of both value and file: (_, 0, RuneTypeEOF, nil) - // end of file in middle of value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.ErrUnexepctedEOF}) - // end of file at start of value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.EOF}) - ReadRuneType() (rune, int, internal.RuneType, error) - // The returned error is a *DecodeReadError, a *DecodeSyntaxError, io.EOF, or nil. - ReadRune() (rune, int, error) - UnreadRune() error - Reset() - InputOffset() int64 -} - -// runeTypeScannerImpl ///////////////////////////////////////////////////////////////////////////// - -type runeTypeScannerImpl struct { +type runeTypeScanner struct { // everything that is not "initialized by constructor" starts // out as the zero value. @@ -47,9 +28,7 @@ type runeTypeScannerImpl struct { rErr error } -var _ runeTypeScanner = (*runeTypeScannerImpl)(nil) - -func (sc *runeTypeScannerImpl) Reset() { +func (sc *runeTypeScanner) Reset() { sc.parser.Reset() if sc.repeat || (sc.rType == internal.RuneTypeEOF && sc.rSize > 0) { sc.repeat = false @@ -69,7 +48,14 @@ func (sc *runeTypeScannerImpl) Reset() { } } -func (sc *runeTypeScannerImpl) ReadRuneType() (rune, int, internal.RuneType, error) { +// The returned error is a *ReadError, a *SyntaxError, or nil. +// An EOF condition is represented as one of: +// +// end of value but not file: (_, >0, RuneTypeEOF, nil) +// end of both value and file: (_, 0, RuneTypeEOF, nil) +// end of file in middle of value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.ErrUnexepctedEOF}) +// end of file at start of value: (_, 0, RuneTypeError, &DecodeSyntaxError{Offset: offset: Err: io.EOF}) +func (sc *runeTypeScanner) ReadRuneType() (rune, int, internal.RuneType, error) { switch { case sc.initialized && (sc.rType == internal.RuneTypeError || sc.rType == internal.RuneTypeEOF): // do nothing @@ -117,24 +103,12 @@ func (sc *runeTypeScannerImpl) ReadRuneType() (rune, int, internal.RuneType, err return sc.rRune, sc.rSize, sc.rType, sc.rErr } -func (sc *runeTypeScannerImpl) ReadRune() (rune, int, error) { - r, s, t, e := sc.ReadRuneType() - switch t { - case internal.RuneTypeEOF: - return 0, 0, io.EOF - case internal.RuneTypeError: - return 0, 0, e - default: - return r, s, nil - } -} - // 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 { +func (sc *runeTypeScanner) UnreadRune() error { if sc.repeat || sc.rSize == 0 { return ErrInvalidUnreadRune } @@ -143,7 +117,7 @@ func (sc *runeTypeScannerImpl) UnreadRune() error { return nil } -func (sc *runeTypeScannerImpl) InputOffset() int64 { +func (sc *runeTypeScanner) InputOffset() int64 { ret := sc.offset if sc.repeat { ret -= int64(sc.rSize) @@ -151,76 +125,37 @@ func (sc *runeTypeScannerImpl) InputOffset() int64 { return ret } -// elemRuneTypeScanner ///////////////////////////////////////////////////////////////////////////// - -type elemRuneTypeScanner struct { - inner runeTypeScanner - - parser internal.Parser - repeat bool - stuck bool - rType internal.RuneType - rErr error +func (sc *runeTypeScanner) PushReadBarrier() { + sc.parser.PushReadBarrier() } -var _ runeTypeScanner = (*elemRuneTypeScanner)(nil) - -func (sc *elemRuneTypeScanner) ReadRuneType() (rune, int, internal.RuneType, error) { - // Read it, run it through the parent's parser. - r, s, t, e := sc.inner.ReadRuneType() - - // Run it through our child parser. - if s > 0 || errors.Is(e, io.ErrUnexpectedEOF) { - if sc.repeat || sc.stuck { - sc.repeat = false - } else { - 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 +func (sc *runeTypeScanner) PopReadBarrier() { + sc.parser.PopBarrier() + if sc.repeat || (sc.rType == internal.RuneTypeEOF && sc.rSize > 0) { + // re-figure the rType and rErr + var err error + sc.rType, err = sc.parser.HandleRune(sc.rRune) + if err != nil { + sc.rErr = &DecodeSyntaxError{ + Offset: sc.offset - int64(sc.rSize), + Err: err, } + } else { + sc.rErr = nil } - sc.stuck = sc.rType == internal.RuneTypeEOF || sc.rType == internal.RuneTypeError - t, e = sc.rType, sc.rErr - } - - // Check if we need to truncate the result. - if t == internal.RuneTypeEOF { - if s > 0 { - _ = sc.inner.UnreadRune() + // tell it to use that rType and rErr + _ = sc.UnreadRune() // we set it up to always succeed + } else if sc.rType == internal.RuneTypeEOF { + // re-figure the rType and rErr + var err error + sc.rType, err = sc.parser.HandleEOF() + if err != nil { + sc.rErr = &DecodeSyntaxError{ + Offset: sc.offset, + Err: err, + } + } else { + sc.rErr = nil } - return 0, 0, internal.RuneTypeEOF, nil } - - return r, s, t, e } - -func (sc *elemRuneTypeScanner) ReadRune() (rune, int, error) { - r, s, t, e := sc.ReadRuneType() - switch t { - case internal.RuneTypeEOF: - return 0, 0, io.EOF - case internal.RuneTypeError: - return 0, 0, e - default: - return r, s, nil - } -} - -func (sc *elemRuneTypeScanner) UnreadRune() error { - ret := sc.inner.UnreadRune() - sc.repeat = true - return ret -} - -func (sc *elemRuneTypeScanner) InputOffset() int64 { return sc.inner.InputOffset() } -func (sc *elemRuneTypeScanner) Reset() {} |