summaryrefslogtreecommitdiff
path: root/reencode.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 /reencode.go
parentbc1bacc410ddfa444c5bf0e56f33a7da440658ae (diff)
Invent "barriers" instead of nesting parsers
Diffstat (limited to 'reencode.go')
-rw-r--r--reencode.go23
1 files changed, 20 insertions, 3 deletions
diff --git a/reencode.go b/reencode.go
index a5dc3c8..eae80db 100644
--- a/reencode.go
+++ b/reencode.go
@@ -106,6 +106,9 @@ type ReEncoder struct {
fracZeros int64
expZero bool
specu *speculation
+
+ // state: .pushBarrier and .popBarrier
+ stackInputPos []int64
}
type speculation struct {
@@ -227,7 +230,7 @@ func (enc *ReEncoder) Close() error {
}
return enc.err
}
- if enc.AllowMultipleValues {
+ if enc.AllowMultipleValues && len(enc.stackInputPos) == 0 {
enc.par.Reset()
}
return nil
@@ -264,7 +267,7 @@ rehandle:
}
enc.err = enc.handleRune(c, t, enc.par.StackSize())
if enc.err == nil && t == internal.RuneTypeEOF {
- if enc.AllowMultipleValues {
+ if enc.AllowMultipleValues && len(enc.stackInputPos) == 0 {
enc.par.Reset()
goto rehandle
} else {
@@ -280,6 +283,20 @@ rehandle:
return enc.written, enc.err
}
+// semi-public API /////////////////////////////////////////////////////////////
+
+func (enc *ReEncoder) pushWriteBarrier() {
+ enc.par.PushWriteBarrier()
+ enc.stackInputPos = append(enc.stackInputPos, enc.inputPos)
+ enc.inputPos = 0
+}
+
+func (enc *ReEncoder) popWriteBarrier() {
+ enc.par.PopBarrier()
+ enc.inputPos += enc.stackInputPos[len(enc.stackInputPos)-1]
+ enc.stackInputPos = enc.stackInputPos[:len(enc.stackInputPos)-1]
+}
+
// internal ////////////////////////////////////////////////////////////////////
func (enc *ReEncoder) handleRune(c rune, t internal.RuneType, stackSize int) error {
@@ -503,7 +520,7 @@ func (enc *ReEncoder) handleRuneMain(c rune, t internal.RuneType) error {
case internal.RuneTypeEOF: // EOF implied by the start of the next top-level value
enc.wasNumber = enc.lastNonSpace.IsNumber()
switch {
- case enc.ForceTrailingNewlines:
+ case enc.ForceTrailingNewlines && len(enc.stackInputPos) == 0:
t = internal.RuneTypeError // enc.lastNonSpace : an NL isn't needed (we already printed one)
err = enc.emitByte('\n')
default: