| | |
| | |
| | |
| |
|
| | |
| |
|
| | package jsontext |
| |
|
| | import ( |
| | "bytes" |
| | "errors" |
| | "math" |
| | "strconv" |
| |
|
| | "encoding/json/internal/jsonflags" |
| | "encoding/json/internal/jsonwire" |
| | ) |
| |
|
| | |
| |
|
| | const ( |
| | maxInt64 = math.MaxInt64 |
| | minInt64 = math.MinInt64 |
| | maxUint64 = math.MaxUint64 |
| | minUint64 = 0 |
| |
|
| | invalidTokenPanic = "invalid jsontext.Token; it has been voided by a subsequent json.Decoder call" |
| | ) |
| |
|
| | var errInvalidToken = errors.New("invalid jsontext.Token") |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type Token struct { |
| | nonComparable |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | raw *decodeBuffer |
| |
|
| | |
| | |
| | |
| | str string |
| |
|
| | |
| | |
| | num uint64 |
| | } |
| |
|
| | |
| |
|
| | var ( |
| | Null Token = rawToken("null") |
| | False Token = rawToken("false") |
| | True Token = rawToken("true") |
| |
|
| | BeginObject Token = rawToken("{") |
| | EndObject Token = rawToken("}") |
| | BeginArray Token = rawToken("[") |
| | EndArray Token = rawToken("]") |
| |
|
| | zeroString Token = rawToken(`""`) |
| | zeroNumber Token = rawToken(`0`) |
| |
|
| | nanString Token = String("NaN") |
| | pinfString Token = String("Infinity") |
| | ninfString Token = String("-Infinity") |
| | ) |
| |
|
| | func rawToken(s string) Token { |
| | return Token{raw: &decodeBuffer{buf: []byte(s), prevStart: 0, prevEnd: len(s)}} |
| | } |
| |
|
| | |
| | func Bool(b bool) Token { |
| | if b { |
| | return True |
| | } |
| | return False |
| | } |
| |
|
| | |
| | |
| | |
| | func String(s string) Token { |
| | if len(s) == 0 { |
| | return zeroString |
| | } |
| | return Token{str: s} |
| | } |
| |
|
| | |
| | |
| | |
| | func Float(n float64) Token { |
| | switch { |
| | case math.Float64bits(n) == 0: |
| | return zeroNumber |
| | case math.IsNaN(n): |
| | return nanString |
| | case math.IsInf(n, +1): |
| | return pinfString |
| | case math.IsInf(n, -1): |
| | return ninfString |
| | } |
| | return Token{str: "f", num: math.Float64bits(n)} |
| | } |
| |
|
| | |
| | func Int(n int64) Token { |
| | if n == 0 { |
| | return zeroNumber |
| | } |
| | return Token{str: "i", num: uint64(n)} |
| | } |
| |
|
| | |
| | func Uint(n uint64) Token { |
| | if n == 0 { |
| | return zeroNumber |
| | } |
| | return Token{str: "u", num: uint64(n)} |
| | } |
| |
|
| | |
| | |
| | func (t Token) Clone() Token { |
| | |
| | if raw := t.raw; raw != nil { |
| | |
| | if t.raw.prevStart == 0 { |
| | switch t.raw { |
| | case Null.raw: |
| | return Null |
| | case False.raw: |
| | return False |
| | case True.raw: |
| | return True |
| | case BeginObject.raw: |
| | return BeginObject |
| | case EndObject.raw: |
| | return EndObject |
| | case BeginArray.raw: |
| | return BeginArray |
| | case EndArray.raw: |
| | return EndArray |
| | } |
| | } |
| |
|
| | if uint64(raw.previousOffsetStart()) != t.num { |
| | panic(invalidTokenPanic) |
| | } |
| | buf := bytes.Clone(raw.previousBuffer()) |
| | return Token{raw: &decodeBuffer{buf: buf, prevStart: 0, prevEnd: len(buf)}} |
| | } |
| | return t |
| | } |
| |
|
| | |
| | |
| | func (t Token) Bool() bool { |
| | switch t.raw { |
| | case True.raw: |
| | return true |
| | case False.raw: |
| | return false |
| | default: |
| | panic("invalid JSON token kind: " + t.Kind().String()) |
| | } |
| | } |
| |
|
| | |
| | |
| | func (t Token) appendString(dst []byte, flags *jsonflags.Flags) ([]byte, error) { |
| | if raw := t.raw; raw != nil { |
| | |
| | buf := raw.previousBuffer() |
| | if Kind(buf[0]) == '"' { |
| | if jsonwire.ConsumeSimpleString(buf) == len(buf) { |
| | return append(dst, buf...), nil |
| | } |
| | dst, _, err := jsonwire.ReformatString(dst, buf, flags) |
| | return dst, err |
| | } |
| | } else if len(t.str) != 0 && t.num == 0 { |
| | |
| | return jsonwire.AppendQuote(dst, t.str, flags) |
| | } |
| |
|
| | panic("invalid JSON token kind: " + t.Kind().String()) |
| | } |
| |
|
| | |
| | |
| | func (t Token) String() string { |
| | |
| | |
| | |
| | |
| | s, b := t.string() |
| | if len(b) > 0 { |
| | return string(b) |
| | } |
| | return s |
| | } |
| | func (t Token) string() (string, []byte) { |
| | if raw := t.raw; raw != nil { |
| | if uint64(raw.previousOffsetStart()) != t.num { |
| | panic(invalidTokenPanic) |
| | } |
| | buf := raw.previousBuffer() |
| | if buf[0] == '"' { |
| | |
| | isVerbatim := jsonwire.ConsumeSimpleString(buf) == len(buf) |
| | return "", jsonwire.UnquoteMayCopy(buf, isVerbatim) |
| | } |
| | |
| | return "", buf |
| | } |
| | if len(t.str) != 0 && t.num == 0 { |
| | return t.str, nil |
| | } |
| | |
| | if t.num > 0 { |
| | switch t.str[0] { |
| | case 'f': |
| | return string(jsonwire.AppendFloat(nil, math.Float64frombits(t.num), 64)), nil |
| | case 'i': |
| | return strconv.FormatInt(int64(t.num), 10), nil |
| | case 'u': |
| | return strconv.FormatUint(uint64(t.num), 10), nil |
| | } |
| | } |
| | return "<invalid jsontext.Token>", nil |
| | } |
| |
|
| | |
| | |
| | func (t Token) appendNumber(dst []byte, flags *jsonflags.Flags) ([]byte, error) { |
| | if raw := t.raw; raw != nil { |
| | |
| | buf := raw.previousBuffer() |
| | if Kind(buf[0]).normalize() == '0' { |
| | dst, _, err := jsonwire.ReformatNumber(dst, buf, flags) |
| | return dst, err |
| | } |
| | } else if t.num != 0 { |
| | |
| | switch t.str[0] { |
| | case 'f': |
| | return jsonwire.AppendFloat(dst, math.Float64frombits(t.num), 64), nil |
| | case 'i': |
| | return strconv.AppendInt(dst, int64(t.num), 10), nil |
| | case 'u': |
| | return strconv.AppendUint(dst, uint64(t.num), 10), nil |
| | } |
| | } |
| |
|
| | panic("invalid JSON token kind: " + t.Kind().String()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (t Token) Float() float64 { |
| | if raw := t.raw; raw != nil { |
| | |
| | if uint64(raw.previousOffsetStart()) != t.num { |
| | panic(invalidTokenPanic) |
| | } |
| | buf := raw.previousBuffer() |
| | if Kind(buf[0]).normalize() == '0' { |
| | fv, _ := jsonwire.ParseFloat(buf, 64) |
| | return fv |
| | } |
| | } else if t.num != 0 { |
| | |
| | switch t.str[0] { |
| | case 'f': |
| | return math.Float64frombits(t.num) |
| | case 'i': |
| | return float64(int64(t.num)) |
| | case 'u': |
| | return float64(uint64(t.num)) |
| | } |
| | } |
| |
|
| | |
| | if t.Kind() == '"' { |
| | switch t.String() { |
| | case "NaN": |
| | return math.NaN() |
| | case "Infinity": |
| | return math.Inf(+1) |
| | case "-Infinity": |
| | return math.Inf(-1) |
| | } |
| | } |
| |
|
| | panic("invalid JSON token kind: " + t.Kind().String()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (t Token) Int() int64 { |
| | if raw := t.raw; raw != nil { |
| | |
| | if uint64(raw.previousOffsetStart()) != t.num { |
| | panic(invalidTokenPanic) |
| | } |
| | neg := false |
| | buf := raw.previousBuffer() |
| | if len(buf) > 0 && buf[0] == '-' { |
| | neg, buf = true, buf[1:] |
| | } |
| | if numAbs, ok := jsonwire.ParseUint(buf); ok { |
| | if neg { |
| | if numAbs > -minInt64 { |
| | return minInt64 |
| | } |
| | return -1 * int64(numAbs) |
| | } else { |
| | if numAbs > +maxInt64 { |
| | return maxInt64 |
| | } |
| | return +1 * int64(numAbs) |
| | } |
| | } |
| | } else if t.num != 0 { |
| | |
| | switch t.str[0] { |
| | case 'i': |
| | return int64(t.num) |
| | case 'u': |
| | if t.num > maxInt64 { |
| | return maxInt64 |
| | } |
| | return int64(t.num) |
| | } |
| | } |
| |
|
| | |
| | if t.Kind() == '0' { |
| | switch fv := t.Float(); { |
| | case fv >= maxInt64: |
| | return maxInt64 |
| | case fv <= minInt64: |
| | return minInt64 |
| | default: |
| | return int64(fv) |
| | } |
| | } |
| |
|
| | panic("invalid JSON token kind: " + t.Kind().String()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (t Token) Uint() uint64 { |
| | |
| | |
| | |
| |
|
| | if raw := t.raw; raw != nil { |
| | |
| | if uint64(raw.previousOffsetStart()) != t.num { |
| | panic(invalidTokenPanic) |
| | } |
| | neg := false |
| | buf := raw.previousBuffer() |
| | if len(buf) > 0 && buf[0] == '-' { |
| | neg, buf = true, buf[1:] |
| | } |
| | if num, ok := jsonwire.ParseUint(buf); ok { |
| | if neg { |
| | return minUint64 |
| | } |
| | return num |
| | } |
| | } else if t.num != 0 { |
| | |
| | switch t.str[0] { |
| | case 'u': |
| | return t.num |
| | case 'i': |
| | if int64(t.num) < minUint64 { |
| | return minUint64 |
| | } |
| | return uint64(int64(t.num)) |
| | } |
| | } |
| |
|
| | |
| | if t.Kind() == '0' { |
| | switch fv := t.Float(); { |
| | case fv >= maxUint64: |
| | return maxUint64 |
| | case fv <= minUint64: |
| | return minUint64 |
| | default: |
| | return uint64(fv) |
| | } |
| | } |
| |
|
| | panic("invalid JSON token kind: " + t.Kind().String()) |
| | } |
| |
|
| | |
| | func (t Token) Kind() Kind { |
| | switch { |
| | case t.raw != nil: |
| | raw := t.raw |
| | if uint64(raw.previousOffsetStart()) != t.num { |
| | panic(invalidTokenPanic) |
| | } |
| | return Kind(t.raw.buf[raw.prevStart]).normalize() |
| | case t.num != 0: |
| | return '0' |
| | case len(t.str) != 0: |
| | return '"' |
| | default: |
| | return invalidKind |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | type Kind byte |
| |
|
| | const ( |
| | KindInvalid Kind = 0 |
| | KindNull Kind = 'n' |
| | KindFalse Kind = 'f' |
| | KindTrue Kind = 't' |
| | KindString Kind = '"' |
| | KindNumber Kind = '0' |
| | KindBeginObject Kind = '{' |
| | KindEndObject Kind = '}' |
| | KindBeginArray Kind = '[' |
| | KindEndArray Kind = ']' |
| | ) |
| |
|
| | const invalidKind Kind = 0 |
| |
|
| | |
| | func (k Kind) String() string { |
| | switch k { |
| | case 0: |
| | return "invalid" |
| | case 'n': |
| | return "null" |
| | case 'f': |
| | return "false" |
| | case 't': |
| | return "true" |
| | case '"': |
| | return "string" |
| | case '0': |
| | return "number" |
| | case '{': |
| | return "{" |
| | case '}': |
| | return "}" |
| | case '[': |
| | return "[" |
| | case ']': |
| | return "]" |
| | default: |
| | return "<invalid jsontext.Kind: " + jsonwire.QuoteRune(string(k)) + ">" |
| | } |
| | } |
| |
|
| | var normKind = [256]Kind{ |
| | 'n': 'n', |
| | 'f': 'f', |
| | 't': 't', |
| | '"': '"', |
| | '{': '{', |
| | '}': '}', |
| | '[': '[', |
| | ']': ']', |
| | '-': '0', |
| | '0': '0', |
| | '1': '0', |
| | '2': '0', |
| | '3': '0', |
| | '4': '0', |
| | '5': '0', |
| | '6': '0', |
| | '7': '0', |
| | '8': '0', |
| | '9': '0', |
| | } |
| |
|
| | |
| | |
| | func (k Kind) normalize() Kind { |
| | |
| | return normKind[k] |
| | } |
| |
|