decode_token.go

  1// Copyright 2019 The Go Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5package json
  6
  7import (
  8	"bytes"
  9	"fmt"
 10	"strconv"
 11)
 12
 13// Kind represents a token kind expressible in the JSON format.
 14type Kind uint16
 15
 16const (
 17	Invalid Kind = (1 << iota) / 2
 18	EOF
 19	Null
 20	Bool
 21	Number
 22	String
 23	Name
 24	ObjectOpen
 25	ObjectClose
 26	ArrayOpen
 27	ArrayClose
 28
 29	// comma is only for parsing in between tokens and
 30	// does not need to be exported.
 31	comma
 32)
 33
 34func (k Kind) String() string {
 35	switch k {
 36	case EOF:
 37		return "eof"
 38	case Null:
 39		return "null"
 40	case Bool:
 41		return "bool"
 42	case Number:
 43		return "number"
 44	case String:
 45		return "string"
 46	case ObjectOpen:
 47		return "{"
 48	case ObjectClose:
 49		return "}"
 50	case Name:
 51		return "name"
 52	case ArrayOpen:
 53		return "["
 54	case ArrayClose:
 55		return "]"
 56	case comma:
 57		return ","
 58	}
 59	return "<invalid>"
 60}
 61
 62// Token provides a parsed token kind and value.
 63//
 64// Values are provided by the difference accessor methods. The accessor methods
 65// Name, Bool, and ParsedString will panic if called on the wrong kind. There
 66// are different accessor methods for the Number kind for converting to the
 67// appropriate Go numeric type and those methods have the ok return value.
 68type Token struct {
 69	// Token kind.
 70	kind Kind
 71	// pos provides the position of the token in the original input.
 72	pos int
 73	// raw bytes of the serialized token.
 74	// This is a subslice into the original input.
 75	raw []byte
 76	// boo is parsed boolean value.
 77	boo bool
 78	// str is parsed string value.
 79	str string
 80}
 81
 82// Kind returns the token kind.
 83func (t Token) Kind() Kind {
 84	return t.kind
 85}
 86
 87// RawString returns the read value in string.
 88func (t Token) RawString() string {
 89	return string(t.raw)
 90}
 91
 92// Pos returns the token position from the input.
 93func (t Token) Pos() int {
 94	return t.pos
 95}
 96
 97// Name returns the object name if token is Name, else it panics.
 98func (t Token) Name() string {
 99	if t.kind == Name {
100		return t.str
101	}
102	panic(fmt.Sprintf("Token is not a Name: %v", t.RawString()))
103}
104
105// Bool returns the bool value if token kind is Bool, else it panics.
106func (t Token) Bool() bool {
107	if t.kind == Bool {
108		return t.boo
109	}
110	panic(fmt.Sprintf("Token is not a Bool: %v", t.RawString()))
111}
112
113// ParsedString returns the string value for a JSON string token or the read
114// value in string if token is not a string.
115func (t Token) ParsedString() string {
116	if t.kind == String {
117		return t.str
118	}
119	panic(fmt.Sprintf("Token is not a String: %v", t.RawString()))
120}
121
122// Float returns the floating-point number if token kind is Number.
123//
124// The floating-point precision is specified by the bitSize parameter: 32 for
125// float32 or 64 for float64. If bitSize=32, the result still has type float64,
126// but it will be convertible to float32 without changing its value. It will
127// return false if the number exceeds the floating point limits for given
128// bitSize.
129func (t Token) Float(bitSize int) (float64, bool) {
130	if t.kind != Number {
131		return 0, false
132	}
133	f, err := strconv.ParseFloat(t.RawString(), bitSize)
134	if err != nil {
135		return 0, false
136	}
137	return f, true
138}
139
140// Int returns the signed integer number if token is Number.
141//
142// The given bitSize specifies the integer type that the result must fit into.
143// It returns false if the number is not an integer value or if the result
144// exceeds the limits for given bitSize.
145func (t Token) Int(bitSize int) (int64, bool) {
146	s, ok := t.getIntStr()
147	if !ok {
148		return 0, false
149	}
150	n, err := strconv.ParseInt(s, 10, bitSize)
151	if err != nil {
152		return 0, false
153	}
154	return n, true
155}
156
157// Uint returns the signed integer number if token is Number.
158//
159// The given bitSize specifies the unsigned integer type that the result must
160// fit into. It returns false if the number is not an unsigned integer value
161// or if the result exceeds the limits for given bitSize.
162func (t Token) Uint(bitSize int) (uint64, bool) {
163	s, ok := t.getIntStr()
164	if !ok {
165		return 0, false
166	}
167	n, err := strconv.ParseUint(s, 10, bitSize)
168	if err != nil {
169		return 0, false
170	}
171	return n, true
172}
173
174func (t Token) getIntStr() (string, bool) {
175	if t.kind != Number {
176		return "", false
177	}
178	parts, ok := parseNumberParts(t.raw)
179	if !ok {
180		return "", false
181	}
182	return normalizeToIntString(parts)
183}
184
185// TokenEquals returns true if given Tokens are equal, else false.
186func TokenEquals(x, y Token) bool {
187	return x.kind == y.kind &&
188		x.pos == y.pos &&
189		bytes.Equal(x.raw, y.raw) &&
190		x.boo == y.boo &&
191		x.str == y.str
192}