summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--adapter_test.go4
-rw-r--r--decode.go504
-rw-r--r--parse.go15
3 files changed, 231 insertions, 292 deletions
diff --git a/adapter_test.go b/adapter_test.go
index b1aec3e..6c57ebc 100644
--- a/adapter_test.go
+++ b/adapter_test.go
@@ -5,7 +5,6 @@
package lowmemjson
import (
- "bufio"
"bytes"
"encoding/json"
"io"
@@ -76,8 +75,7 @@ func init() {
}
func (dec *Decoder) Buffered() io.Reader {
- buf := dec.r.(*bufio.Reader)
- dat, _ := buf.Peek(buf.Buffered())
+ dat, _ := dec.buf.Peek(dec.buf.Buffered())
return bytes.NewReader(dat)
}
diff --git a/decode.go b/decode.go
index 32912ec..0769bc7 100644
--- a/decode.go
+++ b/decode.go
@@ -27,41 +27,54 @@ type runeBuffer interface {
}
type Decoder struct {
- r io.RuneScanner
+ io runeTypeScanner
+ buf *bufio.Reader
// config
disallowUnknownFields bool
useNumber bool
// state
- err error
- curPos int64
- nxtPos int64
- stack []any
+ err error
+ stack []any
}
-var forceBufio bool
+var forceBufio bool // used by the tests to implement .Buffered()
func NewDecoder(r io.Reader) *Decoder {
- rs, ok := r.(io.RuneScanner)
+ rr, ok := r.(io.RuneReader)
+ var ret Decoder
if forceBufio || !ok {
- rs = bufio.NewReader(r)
+ rr = bufio.NewReader(r)
+ if forceBufio {
+ ret.buf = rr.(*bufio.Reader)
+ }
}
- return &Decoder{
- r: rs,
+ ret.io = &noWSRuneTypeScanner{
+ inner: &runeTypeScannerImpl{
+ inner: rr,
+ },
}
+ return &ret
}
func (dec *Decoder) DisallowUnknownFields() { dec.disallowUnknownFields = true }
func (dec *Decoder) UseNumber() { dec.useNumber = true }
-func (dec *Decoder) InputOffset() int64 { return dec.curPos }
+func (dec *Decoder) InputOffset() int64 { return dec.io.InputOffset() }
func (dec *Decoder) More() bool {
- dec.decodeWS()
- _, ok := dec.peekRuneOrEOF()
- return ok
+ dec.io.Reset()
+ _, _, t, e := dec.io.ReadRuneType()
+ dec.io.UnreadRune()
+ return e == nil && t != RuneTypeEOF
}
+func (dec *Decoder) stackPush(idx any) {
+ dec.stack = append(dec.stack, idx)
+}
+func (dec *Decoder) stackPop() {
+ dec.stack = dec.stack[:len(dec.stack)-1]
+}
func (dec *Decoder) stackStr() string {
var buf strings.Builder
buf.WriteString("v")
@@ -71,30 +84,6 @@ func (dec *Decoder) stackStr() string {
return buf.String()
}
-func (dec *Decoder) stackPush(idx any) {
- dec.stack = append(dec.stack, idx)
-}
-func (dec *Decoder) stackPop() {
- dec.stack = dec.stack[:len(dec.stack)-1]
-}
-
-type decodeError struct {
- Err error
-}
-
-func (dec *Decoder) panicIO(err error) {
- panic(decodeError{fmt.Errorf("json: I/O error at input byte %v: %s: %w",
- dec.nxtPos, dec.stackStr(), err)})
-}
-func (dec *Decoder) panicSyntax(err error) {
- panic(decodeError{fmt.Errorf("json: syntax error at input byte %v: %s: %w",
- dec.curPos, dec.stackStr(), err)})
-}
-func (dec *Decoder) panicType(typ reflect.Type, err error) {
- panic(decodeError{fmt.Errorf("json: type mismatch error at input byte %v: %s: type %v: %w",
- dec.curPos, dec.stackStr(), typ, err)})
-}
-
func Decode(r io.Reader, ptr any) error {
return NewDecoder(r).Decode(ptr)
}
@@ -112,6 +101,7 @@ func (dec *Decoder) Decode(ptr any) (err error) {
return dec.err
}
+ dec.io.Reset()
defer func() {
if r := recover(); r != nil {
if de, ok := r.(decodeError); ok {
@@ -122,90 +112,98 @@ func (dec *Decoder) Decode(ptr any) (err error) {
}
}
}()
- dec.decodeWS()
dec.decode(ptrVal.Elem(), false)
return nil
}
-func (dec *Decoder) readRune() rune {
- c, size, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- dec.panicSyntax(io.ErrUnexpectedEOF)
- }
- dec.panicIO(err)
- }
- dec.curPos = dec.nxtPos
- dec.nxtPos = dec.curPos + int64(size)
- return c
+// io helpers //////////////////////////////////////////////////////////////////////////////////////
+
+type decodeError struct {
+ Err error
}
-func (dec *Decoder) readRuneOrEOF() (c rune, ok bool) {
- c, size, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- return 0, false
- }
- dec.panicIO(err)
+func (dec *Decoder) panicType(typ reflect.Type, err error) {
+ panic(decodeError{fmt.Errorf("json: type mismatch error at input byte %v: %s: type %v: %w",
+ dec.InputOffset(), dec.stackStr(), typ, err)})
+}
+
+func (dec *Decoder) readRune() (rune, RuneType) {
+ c, _, t, e := dec.io.ReadRuneType()
+ if e != nil {
+ panic(decodeError{e})
}
- dec.curPos = dec.nxtPos
- dec.nxtPos = dec.curPos + int64(size)
- return c, true
+ return c, t
}
func (dec *Decoder) unreadRune() {
- if err := dec.r.UnreadRune(); err != nil {
+ if err := dec.io.UnreadRune(); err != nil {
// .UnreadRune() must succeed if the previous call was
// .ReadRune(), which it always is for this code.
- panic(err)
+ panic("should not happen")
}
- dec.nxtPos = dec.curPos
}
-func (dec *Decoder) peekRune() rune {
- c, _, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- dec.panicSyntax(io.ErrUnexpectedEOF)
- }
- dec.panicIO(err)
+func (dec *Decoder) peekRuneType() RuneType {
+ _, t := dec.readRune()
+ dec.unreadRune()
+ return t
+}
+
+func (dec *Decoder) expectRune(ec rune, et RuneType) {
+ ac, at := dec.readRune()
+ if ac != ec || at != et {
+ panic("should not happen")
}
- if err := dec.r.UnreadRune(); err != nil {
- // .UnreadRune() must succeed if the previous call was
- // .ReadRune(), which it always is for this code.
- panic(err)
+}
+
+func (dec *Decoder) expectRuneType(ec rune, et RuneType) {
+ ac, at := dec.readRune()
+ if ac != ec || at != et {
+ dec.panicType(nil, fmt.Errorf("TODO error message"))
}
- return c
}
-func (dec *Decoder) peekRuneOrEOF() (rune, bool) {
- c, _, err := dec.r.ReadRune()
- if err != nil {
- if err == io.EOF {
- return 0, false
- }
- dec.panicIO(err)
+type decRuneTypeScanner struct {
+ dec *Decoder
+}
+
+func (sc *decRuneTypeScanner) ReadRuneType() (rune, int, RuneType, error) {
+ c, s, t, e := sc.dec.io.ReadRuneType()
+ if e != nil {
+ panic(decodeError{e})
}
- if err := dec.r.UnreadRune(); err != nil {
- // .UnreadRune() must succeed if the previous call was
- // .ReadRune(), which it always is for this code.
- panic(err)
+ return c, s, t, nil
+}
+func (sc *decRuneTypeScanner) ReadRune() (rune, int, error) {
+ r, s, t, _ := sc.ReadRuneType()
+ switch t {
+ case RuneTypeEOF:
+ return 0, 0, io.EOF
+ default:
+ return r, s, nil
}
- return c, true
}
-func (dec *Decoder) expectRune(exp rune) {
- act := dec.readRune()
- if act != exp {
- dec.panicSyntax(fmt.Errorf("expected %q but got %q", exp, act))
+func (sc *decRuneTypeScanner) UnreadRune() error { return sc.dec.io.UnreadRune() }
+func (sc *decRuneTypeScanner) InputOffset() int64 { return sc.dec.InputOffset() }
+func (sc *decRuneTypeScanner) Reset() { sc.dec.io.Reset() }
+
+func (dec *Decoder) limitingScanner() runeTypeScanner {
+ return &elemRuneTypeScanner{
+ inner: &decRuneTypeScanner{
+ dec: dec,
+ },
}
}
+// decoder main ////////////////////////////////////////////////////////////////////////////////////
+
var (
rawMessagePtrType = reflect.TypeOf((*json.RawMessage)(nil))
decodableType = reflect.TypeOf((*Decodable)(nil)).Elem()
jsonUnmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+ boolType = reflect.TypeOf(true)
)
var kind2bits = map[reflect.Kind]int{
@@ -234,22 +232,22 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
var buf bytes.Buffer
dec.scan(&buf)
if err := val.Addr().Interface().(*json.RawMessage).UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicSyntax(err)
+ dec.panicType(typ, err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(decodableType):
obj := val.Addr().Interface().(Decodable)
- if err := obj.DecodeJSON(dec.r); err != nil {
- dec.panicSyntax(err)
+ if err := obj.DecodeJSON(dec.limitingScanner()); err != nil {
+ dec.panicType(typ, err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(jsonUnmarshalerType):
var buf bytes.Buffer
dec.scan(&buf)
obj := val.Addr().Interface().(json.Unmarshaler)
if err := obj.UnmarshalJSON(buf.Bytes()); err != nil {
- dec.panicSyntax(err)
+ dec.panicType(typ, err)
}
case val.CanAddr() && reflect.PointerTo(typ).Implements(textUnmarshalerType):
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
@@ -257,19 +255,19 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.decodeString(&buf)
obj := val.Addr().Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(buf.Bytes()); err != nil {
- dec.panicSyntax(err)
+ dec.panicType(typ, err)
}
default:
kind := typ.Kind()
switch kind {
case reflect.Bool:
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
val.SetBool(dec.decodeBool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
@@ -277,11 +275,11 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.scanNumber(&buf)
n, err := strconv.ParseInt(buf.String(), 10, kind2bits[kind])
if err != nil {
- dec.panicSyntax(err)
+ dec.panicType(typ, err)
}
val.SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
@@ -289,11 +287,11 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.scanNumber(&buf)
n, err := strconv.ParseUint(buf.String(), 10, kind2bits[kind])
if err != nil {
- dec.panicSyntax(err)
+ dec.panicType(typ, err)
}
val.SetUint(n)
case reflect.Float32, reflect.Float64:
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
@@ -301,11 +299,11 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
dec.scanNumber(&buf)
n, err := strconv.ParseFloat(buf.String(), kind2bits[kind])
if err != nil {
- dec.panicSyntax(err)
+ dec.panicType(typ, err)
}
val.SetFloat(n)
case reflect.String:
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
@@ -321,8 +319,8 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
if typ.NumMethod() > 0 {
dec.panicType(typ, fmt.Errorf("cannot decode in to non-empty interface"))
}
- switch dec.peekRune() {
- case 'n':
+ switch dec.peekRuneType() {
+ case RuneTypeNullN:
if !val.IsNil() && val.Elem().Kind() == reflect.Pointer && val.Elem().Elem().Kind() == reflect.Pointer {
// XXX: I can't justify this case, other than "it's what encoding/json does, but
// I don't understand their rationale".
@@ -339,7 +337,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
}
case reflect.Struct:
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
@@ -372,36 +370,36 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
fVal = fVal.Field(idx)
}
if field.Quote {
- switch dec.peekRune() {
- case 'n':
+ switch dec.peekRuneType() {
+ case RuneTypeNullN:
dec.decodeNull()
switch fVal.Kind() {
// XXX: I can't justify this list, other than "it's what encoding/json
// does, but I don't understand their rationale".
case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice:
fVal.Set(reflect.Zero(fVal.Type()))
+ default:
+ // do nothing???
}
- case '"':
- // TODO: Figure out how to do this without buffering.
+ case RuneTypeStringBeg:
+ // TODO: Figure out how to do this without buffering, have correct offsets.
var buf bytes.Buffer
- subD := *dec // capture the .curPos *before* calling .decodeString
dec.decodeString(&buf)
- subD.r = &buf
+ subD := NewDecoder(&buf)
subD.decode(fVal, false)
default:
- dec.panicSyntax(fmt.Errorf(",string field: expected %q or %q but got %q",
- 'n', '"', dec.peekRune()))
+ dec.panicType(typ, fmt.Errorf(",string field TODO ERROR MESSAGE"))
}
} else {
dec.decode(fVal, true)
}
})
case reflect.Map:
- switch dec.peekRune() {
- case 'n':
+ switch dec.peekRuneType() {
+ case RuneTypeNullN:
dec.decodeNull()
val.Set(reflect.Zero(typ))
- case '{':
+ case RuneTypeObjectBeg:
if val.IsNil() {
val.Set(reflect.MakeMap(typ))
}
@@ -413,7 +411,7 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
case reflect.PointerTo(nameValTyp).Implements(textUnmarshalerType):
obj := nameValPtr.Interface().(encoding.TextUnmarshaler)
if err := obj.UnmarshalText(nameBuf.Bytes()); err != nil {
- dec.panicSyntax(err)
+ dec.panicType(nameValTyp, err)
}
default:
switch nameValTyp.Kind() {
@@ -422,13 +420,13 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()])
if err != nil {
- dec.panicSyntax(err)
+ dec.panicType(nameValTyp, err)
}
nameValPtr.Elem().SetInt(n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(nameBuf.String(), 10, kind2bits[nameValTyp.Kind()])
if err != nil {
- dec.panicSyntax(err)
+ dec.panicType(nameValTyp, err)
}
nameValPtr.Elem().SetUint(n)
default:
@@ -444,16 +442,16 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.SetMapIndex(nameValPtr.Elem(), fValPtr.Elem())
})
default:
- dec.panicSyntax(fmt.Errorf("map: expected %q or %q bug got %q", 'n', '{', dec.peekRune()))
+ dec.panicType(typ, fmt.Errorf("map: TODO"))
}
case reflect.Slice:
switch {
case typ.Elem().Kind() == reflect.Uint8:
- switch dec.peekRune() {
- case 'n':
+ switch dec.peekRuneType() {
+ case RuneTypeNullN:
dec.decodeNull()
val.Set(reflect.Zero(typ))
- case '"':
+ case RuneTypeStringBeg:
var buf bytes.Buffer
dec.decodeString(newBase64Decoder(&buf))
if typ.Elem() == byteType {
@@ -467,14 +465,14 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
}
default:
- dec.panicSyntax(fmt.Errorf("byte slice: expected %q or %q but got %q", 'n', '"', dec.peekRune()))
+ dec.panicType(typ, fmt.Errorf("byte slice: TODO"))
}
default:
- switch dec.peekRune() {
- case 'n':
+ switch dec.peekRuneType() {
+ case RuneTypeNullN:
dec.decodeNull()
val.Set(reflect.Zero(typ))
- case '[':
+ case RuneTypeArrayBeg:
if val.IsNil() {
val.Set(reflect.MakeSlice(typ, 0, 0))
}
@@ -491,11 +489,11 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
i++
})
default:
- dec.panicSyntax(fmt.Errorf("slice: expected %q or %q but got %q", 'n', '[', dec.peekRune()))
+ dec.panicType(typ, fmt.Errorf("slice: TODO"))
}
}
case reflect.Array:
- if nullOK && dec.peekRune() == 'n' {
+ if nullOK && dec.peekRuneType() == RuneTypeNullN {
dec.decodeNull()
return
}
@@ -517,8 +515,8 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
val.Index(i).Set(reflect.Zero(typ.Elem()))
}
case reflect.Pointer:
- switch dec.peekRune() {
- case 'n':
+ switch dec.peekRuneType() {
+ case RuneTypeNullN:
dec.decodeNull()
/*
for typ.Elem().Kind() == reflect.Pointer {
@@ -542,67 +540,27 @@ func (dec *Decoder) decode(val reflect.Value, nullOK bool) {
}
}
-func (dec *Decoder) decodeWS() {
- for {
- c, ok := dec.readRuneOrEOF()
- if !ok {
- return
- }
- switch c {
- // NB: The JSON definition of whitespace is more
- // narrow than unicode.IsSpace
- case 0x0020, 0x000A, 0x000D, 0x0009:
- // do nothing
- default:
- dec.unreadRune()
- return
- }
- }
-}
-
func (dec *Decoder) scan(out io.Writer) {
- var scanner Parser
+ limiter := dec.limitingScanner()
for {
- c, ok := dec.readRuneOrEOF()
-
- var t RuneType
- var err error
- if ok {
- t, err = scanner.HandleRune(c)
- } else {
- t, err = scanner.HandleEOF()
- }
-
- switch t {
- case RuneTypeError:
- dec.panicSyntax(err)
- case RuneTypeEOF:
- if ok {
- dec.unreadRune()
- }
+ c, _, err := limiter.ReadRune()
+ if err == io.EOF {
return
- case RuneTypeSpace:
- // ignore
- default:
- if _, err := writeRune(out, c); err != nil {
- dec.panicIO(err)
- }
}
+ _, _ = writeRune(out, c)
}
}
func (dec *Decoder) scanNumber(out io.Writer) {
- c := dec.peekRune()
- switch c {
- case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- dec.scan(out)
- default:
- dec.panicSyntax(fmt.Errorf("number: expected %q or a digit, but got %q", '-', c))
+ if !dec.peekRuneType().IsNumber() {
+ dec.panicType(numberType, fmt.Errorf("number: not a number"))
}
+ dec.scan(out)
}
func (dec *Decoder) decodeAny() any {
- c := dec.peekRune()
+ c, _ := dec.readRune()
+ dec.unreadRune()
switch c {
case '{':
ret := make(map[string]any)
@@ -628,14 +586,14 @@ func (dec *Decoder) decodeAny() any {
return buf.String()
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
var buf strings.Builder
- dec.scanNumber(&buf)
+ dec.scan(&buf)
num := json.Number(buf.String())
if dec.useNumber {
return num
}
f64, err := num.Float64()
if err != nil {
- dec.panicSyntax(err)
+ panic("should not happen")
}
return f64
case 't', 'f':
@@ -644,168 +602,136 @@ func (dec *Decoder) decodeAny() any {
dec.decodeNull()
return nil
default:
- dec.panicSyntax(fmt.Errorf("any: unexpected character: %c", c))
- panic("not reached")
+ panic("should not happen")
}
}
func (dec *Decoder) decodeObject(nameBuf runeBuffer, decodeKVal func()) {
- dec.expectRune('{')
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case '"':
+ dec.expectRuneType('{', RuneTypeObjectBeg)
+ _, t := dec.readRune()
+ switch t {
+ case RuneTypeObjectEnd:
+ return
+ case RuneTypeStringBeg:
decodeMember:
dec.unreadRune()
nameBuf.Reset()
dec.decodeString(nameBuf)
- dec.decodeWS()
- dec.expectRune(':')
- dec.decodeWS()
+ dec.expectRune(':', RuneTypeObjectColon)
decodeKVal()
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case ',':
- dec.decodeWS()
- dec.expectRune('"')
+ _, t := dec.readRune()
+ switch t {
+ case RuneTypeObjectComma:
+ dec.expectRune('"', RuneTypeStringBeg)
goto decodeMember
- case '}':
+ case RuneTypeObjectEnd:
return
default:
- dec.panicSyntax(fmt.Errorf("object: expected %q or %q but got %q", ',', '}', c))
+ panic("should not happen")
}
- case '}':
- return
default:
- dec.panicSyntax(fmt.Errorf("object: expected %q or %q but got %q", '"', '}', c))
+ panic("should not happen")
}
}
func (dec *Decoder) decodeArray(decodeMember func()) {
- dec.expectRune('[')
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case ']':
+ dec.expectRuneType('[', RuneTypeArrayBeg)
+ _, t := dec.readRune()
+ switch t {
+ case RuneTypeArrayEnd:
return
default:
dec.unreadRune()
decodeNextMember:
decodeMember()
- dec.decodeWS()
- c := dec.readRune()
- switch c {
- case ',':
- dec.decodeWS()
+ _, t := dec.readRune()
+ switch t {
+ case RuneTypeArrayComma:
goto decodeNextMember
- case ']':
+ case RuneTypeArrayEnd:
return
default:
- dec.panicSyntax(fmt.Errorf("array: expected %c or %c but got %c", ',', ']', c))
+ panic("should not happen")
}
}
}
-func (dec *Decoder) decodeHex() rune {
- c := dec.readRune()
- switch {
- case '0' <= c && c <= '9':
- return c - '0'
- case 'a' <= c && c <= 'f':
- return c - 'a' + 10
- case 'A' <= c && c <= 'F':
- return c - 'A' + 10
- default:
- dec.panicSyntax(fmt.Errorf("string: expected a hex digit but got %q", c))
- panic("not reached")
- }
-}
-
func (dec *Decoder) decodeString(out io.Writer) {
- dec.expectRune('"')
+ dec.expectRuneType('"', RuneTypeStringBeg)
+ var uhex [4]byte
for {
- c := dec.readRune()
- switch {
- case 0x0020 <= c && c <= 0x10FFFF && c != '"' && c != '\\':
- if _, err := writeRune(out, c); err != nil {
- dec.panicSyntax(err)
- }
- case c == '\\':
- c = dec.readRune()
+ c, t := dec.readRune()
+ switch t {
+ case RuneTypeStringChar:
+ _, _ = writeRune(out, c)
+ case RuneTypeStringEsc, RuneTypeStringEscU:
+ // do nothing
+ case RuneTypeStringEsc1:
switch c {
case '"':
- if _, err := writeRune(out, '"'); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '"')
case '\\':
- if _, err := writeRune(out, '\\'); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '\\')
case '/':
- if _, err := writeRune(out, '/'); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '/')
case 'b':
- if _, err := writeRune(out, '\b'); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '\b')
case 'f':
- if _, err := writeRune(out, '\f'); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '\f')
case 'n':
- if _, err := writeRune(out, '\n'); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '\n')
case 'r':
- if _, err := writeRune(out, '\r'); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '\r')
case 't':
- if _, err := writeRune(out, '\t'); err != nil {
- dec.panicSyntax(err)
- }
- case 'u':
- c = dec.decodeHex()
- c = (c << 4) | dec.decodeHex()
- c = (c << 4) | dec.decodeHex()
- c = (c << 4) | dec.decodeHex()
- if _, err := writeRune(out, c); err != nil {
- dec.panicSyntax(err)
- }
+ _, _ = writeRune(out, '\t')
+ default:
+ panic("should not happen")
}
- case c == '"':
+ case RuneTypeStringEscUA:
+ uhex[0], _ = hex2int(c)
+ case RuneTypeStringEscUB:
+ uhex[1], _ = hex2int(c)
+ case RuneTypeStringEscUC:
+ uhex[2], _ = hex2int(c)
+ case RuneTypeStringEscUD:
+ uhex[3], _ = hex2int(c)
+ c = 0 |
+ rune(uhex[0])<<12 |
+ rune(uhex[1])<<8 |
+ rune(uhex[2])<<4 |
+ rune(uhex[3])<<0
+ _, _ = writeRune(out, c)
+ case RuneTypeStringEnd:
return
default:
- dec.panicSyntax(fmt.Errorf("string: unexpected %c", c))
+ panic("should not happen")
}
}
}
func (dec *Decoder) decodeBool() bool {
- c := dec.readRune()
+ c, _ := dec.readRune()
switch c {
case 't':
- dec.expectRune('r')
- dec.expectRune('u')
- dec.expectRune('e')
+ dec.expectRune('r', RuneTypeTrueR)
+ dec.expectRune('u', RuneTypeTrueU)
+ dec.expectRune('e', RuneTypeTrueE)
return true
case 'f':
- dec.expectRune('a')
- dec.expectRune('l')
- dec.expectRune('s')
- dec.expectRune('e')
+ dec.expectRune('a', RuneTypeFalseA)
+ dec.expectRune('l', RuneTypeFalseL)
+ dec.expectRune('s', RuneTypeFalseS)
+ dec.expectRune('e', RuneTypeFalseE)
return false
default:
- dec.panicSyntax(fmt.Errorf("bool: expected %q or %q but got %q", 't', 'f', c))
+ dec.panicType(boolType, fmt.Errorf("bool: expected %q or %q but got %q", 't', 'f', c))
panic("not reached")
}
}
func (dec *Decoder) decodeNull() {
- dec.expectRune('n')
- dec.expectRune('u')
- dec.expectRune('l')
- dec.expectRune('l')
+ dec.expectRuneType('n', RuneTypeNullN)
+ dec.expectRune('u', RuneTypeNullU)
+ dec.expectRune('l', RuneTypeNullL1)
+ dec.expectRune('l', RuneTypeNullL2)
}
diff --git a/parse.go b/parse.go
index 9982944..866e9f4 100644
--- a/parse.go
+++ b/parse.go
@@ -184,6 +184,21 @@ func (t RuneType) String() string {
return fmt.Sprintf("<%d>", t)
}
+func (t RuneType) jsonType() string {
+ return map[RuneType]string{
+ RuneTypeObjectBeg: "object",
+ RuneTypeArrayBeg: "array",
+ RuneTypeStringBeg: "string",
+ RuneTypeNumberIntNeg: "number",
+ RuneTypeNumberIntZero: "number",
+ RuneTypeNumberIntDig: "number",
+ RuneTypeTrueT: "true",
+ RuneTypeFalseF: "false",
+ RuneTypeNullN: "null",
+ RuneTypeEOF: "eof",
+ }[t]
+}
+
func (t RuneType) IsNumber() bool {
return RuneTypeNumberIntNeg <= t && t <= RuneTypeNumberExpDig
}