summaryrefslogtreecommitdiff
path: root/reencode.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2022-08-14 10:55:02 -0600
committerLuke Shumaker <lukeshu@datawire.io>2022-08-14 20:30:50 -0600
commit4584172cdf3071cad76a67952f188863e6d4ed91 (patch)
tree58898dbc1015f6536cb0153cda32820e37de8f73 /reencode.go
parentc8a79cbfde0e42ac3d677bb986e4dbfc9e5cfa85 (diff)
reencode: Switch to use Parser
Diffstat (limited to 'reencode.go')
-rw-r--r--reencode.go615
1 files changed, 153 insertions, 462 deletions
diff --git a/reencode.go b/reencode.go
index 66f25da..c4c31a2 100644
--- a/reencode.go
+++ b/reencode.go
@@ -38,15 +38,17 @@ type ReEncoder struct {
bufLen int
// state: .WriteRune
- err error
- inputPos int64
- written int
- stack []reencodeState
- stack0IsNumber bool
- curIndent int
-
- // state: reencodeState-specific
- stateBuf []byte
+ err error
+ par Parser
+ written int
+ inputPos int64
+
+ // state: .handleRune
+ lastNonSpace RuneType
+ curIndent int
+ uhex [4]byte // "\uABCD"-encoded characters in strings
+ fracZeros int64
+ expZero bool
}
// public API //////////////////////////////////////////////////////////////////
@@ -76,24 +78,26 @@ func (enc *ReEncoder) Write(p []byte) (int, error) {
return len(p), nil
}
-func (enc *ReEncoder) Flush() error {
+func (enc *ReEncoder) Close() error {
if enc.bufLen > 0 {
- return &SyntaxError{fmt.Sprintf("EOF: unflushed unicode garbage: %q", enc.buf[:enc.bufLen]), enc.inputPos}
- }
- switch len(enc.stack) {
- case 0:
- return nil
- case 1:
- if enc.stack0IsNumber {
- enc.Compact = true
- return enc.state('\n')
+ return &SyntaxError{
+ Offset: enc.inputPos,
+ msg: fmt.Sprintf("%v: unflushed unicode garbage: %q", io.ErrUnexpectedEOF, enc.buf[:enc.bufLen]),
}
- fallthrough
- default:
- return &SyntaxError{fmt.Sprintf("EOF: in the middle of a value"), enc.inputPos}
}
+ if _, err := enc.par.HandleEOF(); err != nil {
+ enc.err = err
+ return enc.err
+ }
+ if err := enc.handleRune(0, 0); err != nil {
+ enc.err = err
+ return enc.err
+ }
+ return nil
}
+var errBailedAfterCurrent = errors.New("bailed after current")
+
func (enc *ReEncoder) WriteRune(c rune) (n int, err error) {
if enc.err != nil {
return 0, enc.err
@@ -102,497 +106,184 @@ func (enc *ReEncoder) WriteRune(c rune) (n int, err error) {
enc.err = errors.New("lowmemjson.ReEncoder: cannot .WriteRune() when there is a partial rune that has been .Write()n")
return 0, enc.err
}
- enc.written = 0
- enc.err = enc.state(c)
- enc.inputPos += int64(utf8.RuneLen(c))
- return enc.written, enc.err
-}
-
-// io helpers //////////////////////////////////////////////////////////////////
-
-func (enc *ReEncoder) emitByte(c byte) error {
- err := writeByte(enc.Out, c)
- if err == nil {
- enc.written++
- }
- return err
-}
-
-func (enc *ReEncoder) emit(n int, err error) error {
- enc.written += n
- return err
-}
-
-func (enc *ReEncoder) nlIndent() error {
- if enc.Compact || enc.Indent == "" {
- return nil
- }
- if err := enc.emitByte('\n'); err != nil {
- return err
- }
- if enc.prefix != "" {
- if err := enc.emit(io.WriteString(enc.Out, enc.prefix)); err != nil {
- return err
- }
- }
- for i := 0; i < enc.curIndent; i++ {
- if err := enc.emit(io.WriteString(enc.Out, enc.Indent)); err != nil {
- return err
- }
- }
- return nil
-}
-// state helpers ///////////////////////////////////////////////////////////////
-
-func (enc *ReEncoder) pushState(state reencodeState, isNumber bool) {
- if len(enc.stack) == 0 {
- enc.stack0IsNumber = isNumber
- }
- enc.stack = append(enc.stack, state)
-}
-func (enc *ReEncoder) replaceState(state reencodeState, isNumber bool) {
- if len(enc.stack) == 1 {
- enc.stack0IsNumber = isNumber
+ if enc.bailAfterCurrent && len(enc.par.stack) == 0 {
+ return 0, errBailedAfterCurrent
}
- enc.stack[len(enc.stack)-1] = state
-}
-func (enc *ReEncoder) popState() {
- if len(enc.stack) == 1 {
- enc.stack0IsNumber = false
+ t, err := enc.par.HandleRune(c)
+ if err != nil {
+ enc.err = err
+ return 0, enc.err
}
- enc.stack = enc.stack[:len(enc.stack)-1]
-}
-var errBailedAfterCurrent = errors.New("bailed after current")
-
-func (enc *ReEncoder) state(c rune) error {
- if len(enc.stack) == 0 {
- if enc.bailAfterCurrent {
- return errBailedAfterCurrent
- }
- enc.pushState(enc.stateAny, false)
- }
- return enc.stack[len(enc.stack)-1](c)
+ enc.written = 0
+ enc.err = enc.handleRune(c, t)
+ enc.inputPos += int64(utf8.RuneLen(c))
+ return enc.written, enc.err
}
-// any /////////////////////////////////////////////////////////////////////////////////////////////
+// internal ////////////////////////////////////////////////////////////////////
-func (enc *ReEncoder) stateAny(c rune) error {
- switch c {
- case 0x0020, 0x000A, 0x000D, 0x0009:
+func (enc *ReEncoder) handleRune(c rune, t RuneType) error {
+ // whitespace
+ switch t {
+ case RuneTypeSpace:
if enc.Compact || enc.Indent != "" {
return nil
}
- case '{':
- enc.replaceState(enc.stateInEmptyObject, false)
- enc.curIndent++
- case '[':
- enc.replaceState(enc.stateInEmptyArray, false)
- enc.curIndent++
- case '"':
- enc.replaceState(enc.stateInString, false)
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- enc.replaceState(enc.stateNumberA, true)
- return enc.state(c)
- case 't':
- enc.replaceState(enc.stateInTrue, false)
- enc.stateBuf = append(enc.stateBuf[:0], 't')
- case 'f':
- enc.replaceState(enc.stateInFalse, false)
- enc.stateBuf = append(enc.stateBuf[:0], 'f')
- case 'n':
- enc.replaceState(enc.stateInNull, false)
- enc.stateBuf = append(enc.stateBuf[:0], 'n')
- default:
- return &SyntaxError{fmt.Sprintf("any: unexpected character: %c", c), enc.inputPos}
}
- return enc.emitByte(byte(c))
-}
-// object //////////////////////////////////////////////////////////////////////////////////////////
+ defer func() {
+ enc.lastNonSpace = t
+ }()
-func (enc *ReEncoder) stateInEmptyObject(c rune) error { return enc._stateInObject(c, false) }
-func (enc *ReEncoder) stateInNonEmptyObject(c rune) error { return enc._stateInObject(c, true) }
-func (enc *ReEncoder) _stateInObject(c rune, nonempty bool) error {
- switch c {
- case 0x0020, 0x000A, 0x000D, 0x0009:
- if enc.Compact || enc.Indent != "" {
+ // shorten numbers
+ switch t { // trim trailing '0's from the fraction-part, but don't remove all digits
+ case RuneTypeNumberFracDot:
+ enc.fracZeros = 0
+ case RuneTypeNumberFracDig:
+ if c == '0' && enc.lastNonSpace == RuneTypeNumberFracDig {
+ enc.fracZeros++
return nil
}
- case '"':
- if err := enc.nlIndent(); err != nil {
- return err
- }
- enc.replaceState(enc.stateInKV, false)
- enc.pushState(enc.stateInString, false)
- case '}':
- enc.popState()
- enc.curIndent--
- if nonempty {
- if err := enc.nlIndent(); err != nil {
+ fallthrough
+ default:
+ for enc.fracZeros > 0 {
+ if err := enc.emitByte('0'); err != nil {
return err
}
+ enc.fracZeros--
}
- default:
- return &SyntaxError{fmt.Sprintf("object: unexpected character: %c", c), enc.inputPos}
}
- return enc.emitByte(byte(c))
-}
-func (enc *ReEncoder) stateInKV(c rune) error {
- switch c {
- case 0x0020, 0x000A, 0x000D, 0x0009:
- if enc.Compact || enc.Indent != "" {
+ switch t { // trim leading '0's from the exponent-part, but don't remove all digits
+ case RuneTypeNumberExpE, RuneTypeNumberExpSign:
+ enc.expZero = true
+ case RuneTypeNumberExpDig:
+ if c == '0' && enc.expZero {
return nil
}
- return enc.emitByte(byte(c))
- case ':':
- enc.replaceState(enc.stateAfterV, false)
- enc.pushState(enc.stateAny, false)
- if err := enc.emitByte(byte(c)); err != nil {
- return err
- }
- if !enc.Compact && enc.Indent != "" {
- return enc.emitByte(' ')
- }
- return nil
+ enc.expZero = false
default:
- return &SyntaxError{fmt.Sprintf("object member: unexpected character: %c", c), enc.inputPos}
- }
-}
-func (enc *ReEncoder) stateAfterV(c rune) error {
- switch c {
- case 0x0020, 0x000A, 0x000D, 0x0009:
- if enc.Compact || enc.Indent != "" {
- return nil
- }
- case ',':
- enc.replaceState(enc.stateInNonEmptyObject, false)
- case '}':
- enc.popState()
- enc.curIndent--
- if err := enc.nlIndent(); err != nil {
- return err
+ if enc.expZero {
+ if err := enc.emitByte('0'); err != nil {
+ return err
+ }
+ enc.expZero = false
}
- default:
- return &SyntaxError{fmt.Sprintf("object member: unexpected character: %c", c), enc.inputPos}
}
- return enc.emitByte(byte(c))
-}
-
-// array ///////////////////////////////////////////////////////////////////////////////////////////
-func (enc *ReEncoder) stateInEmptyArray(c rune) error { return enc._stateInArray(c, false) }
-func (enc *ReEncoder) stateInNonEmptyArray(c rune) error { return enc._stateInArray(c, true) }
-func (enc *ReEncoder) _stateInArray(c rune, nonempty bool) error {
- switch c {
- case 0x0020, 0x000A, 0x000D, 0x0009:
- if enc.Compact || enc.Indent != "" {
- return nil
- }
- case ']':
- enc.popState()
+ // indent
+ switch t {
+ case RuneTypeObjectBeg, RuneTypeArrayBeg:
+ enc.curIndent++
+ case RuneTypeObjectEnd, RuneTypeArrayEnd:
enc.curIndent--
- if nonempty {
- if err := enc.nlIndent(); err != nil {
+ switch enc.lastNonSpace {
+ case RuneTypeObjectBeg, RuneTypeArrayEnd:
+ // collapse
+ default:
+ if err := enc.emitNlIndent(); err != nil {
return err
}
}
- default:
- if err := enc.nlIndent(); err != nil {
- return err
- }
- enc.replaceState(enc.stateAfterItem, false)
- enc.pushState(enc.stateAny, false)
- return enc.state(c)
- }
- return enc.emitByte(byte(c))
-}
-func (enc *ReEncoder) stateAfterItem(c rune) error {
- switch c {
- case 0x0020, 0x000A, 0x000D, 0x0009:
- if enc.Compact || enc.Indent != "" {
- return nil
- }
- case ',':
- enc.replaceState(enc.stateInNonEmptyArray, false)
- case ']':
- enc.popState()
- enc.curIndent--
- if err := enc.nlIndent(); err != nil {
- return err
+ case RuneTypeObjectColon:
+ if !enc.Compact && enc.Indent != "" {
+ if err := enc.emitByte(':'); err != nil {
+ return err
+ }
+ return enc.emitByte(' ')
}
default:
- return &SyntaxError{fmt.Sprintf("array: unexpected character: %c", c), enc.inputPos}
+ switch enc.lastNonSpace {
+ case RuneTypeObjectBeg, RuneTypeObjectComma, RuneTypeArrayBeg, RuneTypeArrayComma:
+ if err := enc.emitNlIndent(); err != nil {
+ return err
+ }
+ }
}
- return enc.emitByte(byte(c))
-}
-// string //////////////////////////////////////////////////////////////////////////////////////////
+ // main
+ switch t {
-func (enc *ReEncoder) stateInString(c rune) error {
- switch {
- case c == '\\':
- enc.replaceState(enc.stateInBackslash, false)
- return nil
- case c == '"':
- enc.popState()
- return enc.emitByte(byte(c))
- case 0x0020 <= c && c <= 0x10FFFF:
+ case RuneTypeStringChar:
return enc.emit(writeStringChar(enc.Out, c, BackslashEscapeNone, enc.BackslashEscape))
- default:
- return &SyntaxError{fmt.Sprintf("string: unexpected character: %c", c), enc.inputPos}
- }
-}
-func (enc *ReEncoder) stateInBackslash(c rune) error {
- switch c {
- case '"':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '"', BackslashEscapeShort, enc.BackslashEscape))
- case '\\':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '\\', BackslashEscapeShort, enc.BackslashEscape))
- case '/':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '/', BackslashEscapeShort, enc.BackslashEscape))
- case 'b':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '\b', BackslashEscapeShort, enc.BackslashEscape))
- case 'f':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '\f', BackslashEscapeShort, enc.BackslashEscape))
- case 'n':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '\n', BackslashEscapeShort, enc.BackslashEscape))
- case 'r':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '\r', BackslashEscapeShort, enc.BackslashEscape))
- case 't':
- enc.replaceState(enc.stateInString, false)
- return enc.emit(writeStringChar(enc.Out, '\t', BackslashEscapeShort, enc.BackslashEscape))
- case 'u':
- enc.replaceState(enc.stateInUnicode, false)
+ case RuneTypeStringEsc, RuneTypeStringEscU:
return nil
- default:
- return &SyntaxError{fmt.Sprintf("string backslash sequence: unexpected character: %c", c), enc.inputPos}
- }
-}
-func (enc *ReEncoder) stateInUnicode(c rune) error {
- switch {
- case '0' <= c && c <= '9':
- enc.stateBuf = append(enc.stateBuf, byte(c)-'0')
- case 'a' <= c && c <= 'f':
- enc.stateBuf = append(enc.stateBuf, byte(c)-'a'+10)
- case 'A' <= c && c <= 'F':
- enc.stateBuf = append(enc.stateBuf, byte(c)-'A'+10)
- default:
- return &SyntaxError{fmt.Sprintf("string unicode sequence: unexpected character: %c", c), enc.inputPos}
- }
- if len(enc.stateBuf) == 4 {
- enc.replaceState(enc.stateInString, false)
+ case RuneTypeStringEsc1:
+ switch c {
+ case '"':
+ return enc.emit(writeStringChar(enc.Out, '"', BackslashEscapeShort, enc.BackslashEscape))
+ case '\\':
+ return enc.emit(writeStringChar(enc.Out, '\\', BackslashEscapeShort, enc.BackslashEscape))
+ case '/':
+ return enc.emit(writeStringChar(enc.Out, '/', BackslashEscapeShort, enc.BackslashEscape))
+ case 'b':
+ return enc.emit(writeStringChar(enc.Out, '\b', BackslashEscapeShort, enc.BackslashEscape))
+ case 'f':
+ return enc.emit(writeStringChar(enc.Out, '\f', BackslashEscapeShort, enc.BackslashEscape))
+ case 'n':
+ return enc.emit(writeStringChar(enc.Out, '\n', BackslashEscapeShort, enc.BackslashEscape))
+ case 'r':
+ return enc.emit(writeStringChar(enc.Out, '\r', BackslashEscapeShort, enc.BackslashEscape))
+ case 't':
+ return enc.emit(writeStringChar(enc.Out, '\t', BackslashEscapeShort, enc.BackslashEscape))
+ default:
+ panic("should not happen")
+ }
+ case RuneTypeStringEscUA:
+ enc.uhex[0], _ = hex2int(c)
+ return nil
+ case RuneTypeStringEscUB:
+ enc.uhex[1], _ = hex2int(c)
+ return nil
+ case RuneTypeStringEscUC:
+ enc.uhex[2], _ = hex2int(c)
+ return nil
+ case RuneTypeStringEscUD:
+ enc.uhex[3], _ = hex2int(c)
c := 0 |
- rune(enc.stateBuf[0])<<12 |
- rune(enc.stateBuf[1])<<8 |
- rune(enc.stateBuf[2])<<4 |
- rune(enc.stateBuf[3])<<0
- enc.stateBuf = enc.stateBuf[:0]
+ rune(enc.uhex[0])<<12 |
+ rune(enc.uhex[1])<<8 |
+ rune(enc.uhex[2])<<4 |
+ rune(enc.uhex[3])<<0
return enc.emit(writeStringChar(enc.Out, c, BackslashEscapeUnicode, enc.BackslashEscape))
- }
- return nil
-}
-
-// number //////////////////////////////////////////////////////////////////////////////////////////
-// Here's a flattened drawing of the syntax diagram from www.json.org :
-//
-// [------------ integer ----------][-- fraction ---][-------- exponent -------]
-// >─╮─────╭─╮─"0"───────╭─────────╭──╮─────────────╭──╮───────────────────────╭─>
-// │ │ │ │ │ │ │ │ │
-// ╰─"-"─╯ ╰─digit 1-9─╯─╭digit╮─╯ ╰─"."─╭digit╮─╯ ╰─"e"─╭─╮─────╭─╭digit╮─╯
-// ╰──<──╯ ╰──<──╯ │ │ │ │ ╰──<──╯
-// ╰─"E"─╯ ╰─"-"─╯
-// │ │
-// ╰─"+"─╯
-//
-// Now here it is slightly redrawn, and with each distinct state our
-// decoder can be in marked with a single-capital-letter:
-//
-// [-------------- integer ------------][--------- fraction --------][--------- exponent ---------]
-// >─A─╮───────╭──╮─"0"─────────C─╭─────────╮──────────────────╭─────────╮──────────────────────────╭─>
-// │ │ │ │ │ │ │ │
-// ╰─"-"─B─╯ ╰─digit 1-9─╭─D─╯─digit╮ ╰─"."─E─digit──╭─F─╯─digit╮ ╰─"e"─╭─G─╮─────╭─╭digit─H─╯
-// ╰────<─────╯ ╰────<─────╯ │ │ │ │ ╰────<───╯
-// ╰─"E"─╯ ╰─"-"─╯
-// │ │
-// ╰─"+"─╯
-//
-// Which state we're at is the 'X' in 'stateNumberX'.
-//
-// Besides just traversing that, there are a few compressions we want to make:
-//
-// - trim trailing 0s from fraction the (but don't remove the
-// fraction if it's all 0s); do this by making the F state a little
-// special. This requires a little more state, because when we
-// encounter the 0 we don't yet know if it's trailing. So, store
-// the number of maybe-trailing zeros in enc.stateBuf[0]; if that
-// reaches 255, then bleed over to enc.stateBuf[1] and so on.
-//
-// - trim leading 0s from the exponent (but don't remove the exponent
-// if it's all 0s); do this by making the H state a little special.
-// Record whether we've seen a non-zero digit in enc.stateBuf[0]
-// (0=false, 1=true).
-
-// integer-part ////////////////////////////////////////////////////////////////
-func (enc *ReEncoder) stateNumberA(c rune) error { // start
- switch c {
- case '-':
- enc.replaceState(enc.stateNumberB, true)
- case '0':
- enc.replaceState(enc.stateNumberC, true)
- case '1', '2', '3', '4', '5', '6', '7', '8', '9':
- enc.replaceState(enc.stateNumberD, true)
- default:
- return &SyntaxError{fmt.Sprintf("number: unexpected character: %c", c), enc.inputPos}
- }
- return enc.emitByte(byte(c))
-}
-func (enc *ReEncoder) stateNumberB(c rune) error { // got a leading "-"
- switch c {
- case '0':
- enc.replaceState(enc.stateNumberC, true)
- case '1', '2', '3', '4', '5', '6', '7', '8', '9':
- enc.replaceState(enc.stateNumberD, true)
- default:
- return &SyntaxError{fmt.Sprintf("number: unexpected character: %c", c), enc.inputPos}
- }
- return enc.emitByte(byte(c))
-}
-func (enc *ReEncoder) stateNumberC(c rune) error { // ready for the fraction or exponent part to start
- switch c {
- case '.':
- enc.replaceState(enc.stateNumberE, true)
- return enc.emitByte('.')
- case 'e', 'E':
- enc.replaceState(enc.stateNumberG, true)
- enc.stateBuf = append(enc.stateBuf[:0], 0)
- return enc.emitByte('e')
+ case RuneTypeError: // EOF
+ return nil
default:
- enc.popState()
- return enc.state(c)
- }
-}
-func (enc *ReEncoder) stateNumberD(c rune) error { // in the integer part
- switch c {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return enc.emitByte(byte(c))
- case '.':
- enc.replaceState(enc.stateNumberE, true)
- return enc.emitByte('.')
- case 'e', 'E':
- enc.replaceState(enc.stateNumberG, true)
- enc.stateBuf = append(enc.stateBuf[:0], 0)
- return enc.emitByte('e')
- default:
- enc.popState()
- return enc.state(c)
}
}
-// fraction-part ///////////////////////////////////////////////////////////////
-func (enc *ReEncoder) stateNumberE(c rune) error { // got a ".", ready to read a number for the fraction part
- switch c {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- enc.replaceState(enc.stateNumberF, true)
- return enc.emitByte(byte(c))
- default:
- return &SyntaxError{fmt.Sprintf("number: unexpected character: %c", c), enc.inputPos}
+func (enc *ReEncoder) emitByte(c byte) error {
+ err := writeByte(enc.Out, c)
+ if err == nil {
+ enc.written++
}
+ return err
}
-func (enc *ReEncoder) stateNumberF(c rune) error { // in the fraction part
- switch c {
- case '0':
- if len(enc.stateBuf) > 0 && enc.stateBuf[len(enc.stateBuf)-1] < 255 {
- enc.stateBuf[len(enc.stateBuf)-1]++
- } else {
- enc.stateBuf = append(enc.stateBuf, 1)
- }
- return nil
- case '1', '2', '3', '4', '5', '6', '7', '8', '9':
- for len(enc.stateBuf) > 0 {
- if err := enc.emitByte('0'); err != nil {
- return err
- }
- if enc.stateBuf[len(enc.stateBuf)-1] == 1 {
- enc.stateBuf = enc.stateBuf[:len(enc.stateBuf)-1]
- } else {
- enc.stateBuf[len(enc.stateBuf)-1]--
- }
- }
- return enc.emitByte(byte(c))
- case 'e', 'E':
- enc.replaceState(enc.stateNumberG, true)
- enc.stateBuf = append(enc.stateBuf[:0], 0)
- return enc.emitByte('e')
- default:
- enc.stateBuf = enc.stateBuf[:0]
- enc.popState()
- return enc.state(c)
- }
+
+func (enc *ReEncoder) emit(n int, err error) error {
+ enc.written += n
+ return err
}
-// exponent-part ///////////////////////////////////////////////////////////////
-func (enc *ReEncoder) stateNumberG(c rune) error { // got a leading "e"
- switch c {
- case '-', '+':
- enc.replaceState(enc.stateNumberH, true)
- return enc.emitByte(byte(c))
- case '0':
- enc.replaceState(enc.stateNumberH, true)
+func (enc *ReEncoder) emitNlIndent() error {
+ if enc.Compact || enc.Indent == "" {
return nil
- case '1', '2', '3', '4', '5', '6', '7', '8', '9':
- enc.replaceState(enc.stateNumberH, true)
- enc.stateBuf[0] = 1
- return enc.emitByte(byte(c))
- default:
- enc.stateBuf = enc.stateBuf[:0]
- return &SyntaxError{fmt.Sprintf("number: unexpected character: %c", c), enc.inputPos}
}
-}
-func (enc *ReEncoder) stateNumberH(c rune) error { // in the exponent's number part
- switch c {
- case '0':
- if enc.stateBuf[0] == 0 {
- return nil
- }
- return enc.emitByte('0')
- case '1', '2', '3', '4', '5', '6', '7', '8', '9':
- enc.stateBuf[0] = 1
- return enc.emitByte(byte(c))
- default:
- if enc.stateBuf[0] == 0 {
- if err := enc.emitByte('0'); err != nil {
- return err
- }
- }
- enc.stateBuf = enc.stateBuf[:0]
- enc.popState()
- return enc.state(c)
+ if err := enc.emitByte('\n'); err != nil {
+ return err
}
-}
-
-// literals ////////////////////////////////////////////////////////////////////////////////////////
-
-func (enc *ReEncoder) stateInTrue(c rune) error { return enc._stateInLiteral(c, "true") }
-func (enc *ReEncoder) stateInFalse(c rune) error { return enc._stateInLiteral(c, "false") }
-func (enc *ReEncoder) stateInNull(c rune) error { return enc._stateInLiteral(c, "null") }
-func (enc *ReEncoder) _stateInLiteral(c rune, full string) error {
- if c != rune(full[len(enc.stateBuf)]) {
- return &SyntaxError{fmt.Sprintf("%s: unexpected character: %c", full, c), enc.inputPos}
+ if enc.prefix != "" {
+ if err := enc.emit(io.WriteString(enc.Out, enc.prefix)); err != nil {
+ return err
+ }
}
- enc.stateBuf = append(enc.stateBuf, byte(c))
- if len(enc.stateBuf) == len(full) {
- enc.stateBuf = enc.stateBuf[:0]
- enc.popState()
+ for i := 0; i < enc.curIndent; i++ {
+ if err := enc.emit(io.WriteString(enc.Out, enc.Indent)); err != nil {
+ return err
+ }
}
- return enc.emitByte(byte(c))
+ return nil
}