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 5 package json
6 7 import (
8 "bytes"
9 "fmt"
10 "strconv"
11 )
12 13 // Kind represents a token kind expressible in the JSON format.
14 type Kind uint16
15 16 const (
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 34 func (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.
68 type 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.
83 func (t Token) Kind() Kind {
84 return t.kind
85 }
86 87 // RawString returns the read value in string.
88 func (t Token) RawString() string {
89 return string(t.raw)
90 }
91 92 // Pos returns the token position from the input.
93 func (t Token) Pos() int {
94 return t.pos
95 }
96 97 // Name returns the object name if token is Name, else it panics.
98 func (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.
106 func (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.
115 func (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.
129 func (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.
145 func (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.
162 func (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 174 func (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.
186 func 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 }
193