decode_token.go raw

   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