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} 193