blob: 50578d6593c10c14c1d3923cb72a8017775f79af [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// 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}