blob: 2eb7023b2fcfefd8aa21f802d70e23995bb5f151 [file] [log] [blame]
amit.ghosh258d14c2020-10-02 15:13:38 +02001// 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 will return an error.
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, else it will
158// return an error.
159//
160// The given bitSize specifies the unsigned integer type that the result must
161// fit into. It returns false if the number is not an unsigned integer value
162// or if the result exceeds the limits for given bitSize.
163func (t Token) Uint(bitSize int) (uint64, bool) {
164 s, ok := t.getIntStr()
165 if !ok {
166 return 0, false
167 }
168 n, err := strconv.ParseUint(s, 10, bitSize)
169 if err != nil {
170 return 0, false
171 }
172 return n, true
173}
174
175func (t Token) getIntStr() (string, bool) {
176 if t.kind != Number {
177 return "", false
178 }
179 parts, ok := parseNumberParts(t.raw)
180 if !ok {
181 return "", false
182 }
183 return normalizeToIntString(parts)
184}
185
186// TokenEquals returns true if given Tokens are equal, else false.
187func TokenEquals(x, y Token) bool {
188 return x.kind == y.kind &&
189 x.pos == y.pos &&
190 bytes.Equal(x.raw, y.raw) &&
191 x.boo == y.boo &&
192 x.str == y.str
193}