summaryrefslogtreecommitdiff
path: root/decode_scan.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2023-01-29 20:59:37 -0700
committerLuke Shumaker <lukeshu@lukeshu.com>2023-01-30 22:56:40 -0700
commitb3f4186f2b8e992f56f898784b1cd28bfd7550ca (patch)
tree9c9f0086c386a63a12b622945248916d51c480a5 /decode_scan.go
parentbc1bacc410ddfa444c5bf0e56f33a7da440658ae (diff)
Invent "barriers" instead of nesting parsers
Diffstat (limited to 'decode_scan.go')
-rw-r--r--decode_scan.go143
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() {}