xref: /aosp_15_r20/external/golang-protobuf/internal/encoding/text/decode_token.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2018 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage text
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"bytes"
9*1c12ee1eSDan Willemsen	"fmt"
10*1c12ee1eSDan Willemsen	"math"
11*1c12ee1eSDan Willemsen	"strconv"
12*1c12ee1eSDan Willemsen	"strings"
13*1c12ee1eSDan Willemsen
14*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/flags"
15*1c12ee1eSDan Willemsen)
16*1c12ee1eSDan Willemsen
17*1c12ee1eSDan Willemsen// Kind represents a token kind expressible in the textproto format.
18*1c12ee1eSDan Willemsentype Kind uint8
19*1c12ee1eSDan Willemsen
20*1c12ee1eSDan Willemsen// Kind values.
21*1c12ee1eSDan Willemsenconst (
22*1c12ee1eSDan Willemsen	Invalid Kind = iota
23*1c12ee1eSDan Willemsen	EOF
24*1c12ee1eSDan Willemsen	Name   // Name indicates the field name.
25*1c12ee1eSDan Willemsen	Scalar // Scalar are scalar values, e.g. "string", 47, ENUM_LITERAL, true.
26*1c12ee1eSDan Willemsen	MessageOpen
27*1c12ee1eSDan Willemsen	MessageClose
28*1c12ee1eSDan Willemsen	ListOpen
29*1c12ee1eSDan Willemsen	ListClose
30*1c12ee1eSDan Willemsen
31*1c12ee1eSDan Willemsen	// comma and semi-colon are only for parsing in between values and should not be exposed.
32*1c12ee1eSDan Willemsen	comma
33*1c12ee1eSDan Willemsen	semicolon
34*1c12ee1eSDan Willemsen
35*1c12ee1eSDan Willemsen	// bof indicates beginning of file, which is the default token
36*1c12ee1eSDan Willemsen	// kind at the beginning of parsing.
37*1c12ee1eSDan Willemsen	bof = Invalid
38*1c12ee1eSDan Willemsen)
39*1c12ee1eSDan Willemsen
40*1c12ee1eSDan Willemsenfunc (t Kind) String() string {
41*1c12ee1eSDan Willemsen	switch t {
42*1c12ee1eSDan Willemsen	case Invalid:
43*1c12ee1eSDan Willemsen		return "<invalid>"
44*1c12ee1eSDan Willemsen	case EOF:
45*1c12ee1eSDan Willemsen		return "eof"
46*1c12ee1eSDan Willemsen	case Scalar:
47*1c12ee1eSDan Willemsen		return "scalar"
48*1c12ee1eSDan Willemsen	case Name:
49*1c12ee1eSDan Willemsen		return "name"
50*1c12ee1eSDan Willemsen	case MessageOpen:
51*1c12ee1eSDan Willemsen		return "{"
52*1c12ee1eSDan Willemsen	case MessageClose:
53*1c12ee1eSDan Willemsen		return "}"
54*1c12ee1eSDan Willemsen	case ListOpen:
55*1c12ee1eSDan Willemsen		return "["
56*1c12ee1eSDan Willemsen	case ListClose:
57*1c12ee1eSDan Willemsen		return "]"
58*1c12ee1eSDan Willemsen	case comma:
59*1c12ee1eSDan Willemsen		return ","
60*1c12ee1eSDan Willemsen	case semicolon:
61*1c12ee1eSDan Willemsen		return ";"
62*1c12ee1eSDan Willemsen	default:
63*1c12ee1eSDan Willemsen		return fmt.Sprintf("<invalid:%v>", uint8(t))
64*1c12ee1eSDan Willemsen	}
65*1c12ee1eSDan Willemsen}
66*1c12ee1eSDan Willemsen
67*1c12ee1eSDan Willemsen// NameKind represents different types of field names.
68*1c12ee1eSDan Willemsentype NameKind uint8
69*1c12ee1eSDan Willemsen
70*1c12ee1eSDan Willemsen// NameKind values.
71*1c12ee1eSDan Willemsenconst (
72*1c12ee1eSDan Willemsen	IdentName NameKind = iota + 1
73*1c12ee1eSDan Willemsen	TypeName
74*1c12ee1eSDan Willemsen	FieldNumber
75*1c12ee1eSDan Willemsen)
76*1c12ee1eSDan Willemsen
77*1c12ee1eSDan Willemsenfunc (t NameKind) String() string {
78*1c12ee1eSDan Willemsen	switch t {
79*1c12ee1eSDan Willemsen	case IdentName:
80*1c12ee1eSDan Willemsen		return "IdentName"
81*1c12ee1eSDan Willemsen	case TypeName:
82*1c12ee1eSDan Willemsen		return "TypeName"
83*1c12ee1eSDan Willemsen	case FieldNumber:
84*1c12ee1eSDan Willemsen		return "FieldNumber"
85*1c12ee1eSDan Willemsen	default:
86*1c12ee1eSDan Willemsen		return fmt.Sprintf("<invalid:%v>", uint8(t))
87*1c12ee1eSDan Willemsen	}
88*1c12ee1eSDan Willemsen}
89*1c12ee1eSDan Willemsen
90*1c12ee1eSDan Willemsen// Bit mask in Token.attrs to indicate if a Name token is followed by the
91*1c12ee1eSDan Willemsen// separator char ':'. The field name separator char is optional for message
92*1c12ee1eSDan Willemsen// field or repeated message field, but required for all other types. Decoder
93*1c12ee1eSDan Willemsen// simply indicates whether a Name token is followed by separator or not.  It is
94*1c12ee1eSDan Willemsen// up to the prototext package to validate.
95*1c12ee1eSDan Willemsenconst hasSeparator = 1 << 7
96*1c12ee1eSDan Willemsen
97*1c12ee1eSDan Willemsen// Scalar value types.
98*1c12ee1eSDan Willemsenconst (
99*1c12ee1eSDan Willemsen	numberValue = iota + 1
100*1c12ee1eSDan Willemsen	stringValue
101*1c12ee1eSDan Willemsen	literalValue
102*1c12ee1eSDan Willemsen)
103*1c12ee1eSDan Willemsen
104*1c12ee1eSDan Willemsen// Bit mask in Token.numAttrs to indicate that the number is a negative.
105*1c12ee1eSDan Willemsenconst isNegative = 1 << 7
106*1c12ee1eSDan Willemsen
107*1c12ee1eSDan Willemsen// Token provides a parsed token kind and value. Values are provided by the
108*1c12ee1eSDan Willemsen// different accessor methods.
109*1c12ee1eSDan Willemsentype Token struct {
110*1c12ee1eSDan Willemsen	// Kind of the Token object.
111*1c12ee1eSDan Willemsen	kind Kind
112*1c12ee1eSDan Willemsen	// attrs contains metadata for the following Kinds:
113*1c12ee1eSDan Willemsen	// Name: hasSeparator bit and one of NameKind.
114*1c12ee1eSDan Willemsen	// Scalar: one of numberValue, stringValue, literalValue.
115*1c12ee1eSDan Willemsen	attrs uint8
116*1c12ee1eSDan Willemsen	// numAttrs contains metadata for numberValue:
117*1c12ee1eSDan Willemsen	// - highest bit is whether negative or positive.
118*1c12ee1eSDan Willemsen	// - lower bits indicate one of numDec, numHex, numOct, numFloat.
119*1c12ee1eSDan Willemsen	numAttrs uint8
120*1c12ee1eSDan Willemsen	// pos provides the position of the token in the original input.
121*1c12ee1eSDan Willemsen	pos int
122*1c12ee1eSDan Willemsen	// raw bytes of the serialized token.
123*1c12ee1eSDan Willemsen	// This is a subslice into the original input.
124*1c12ee1eSDan Willemsen	raw []byte
125*1c12ee1eSDan Willemsen	// str contains parsed string for the following:
126*1c12ee1eSDan Willemsen	// - stringValue of Scalar kind
127*1c12ee1eSDan Willemsen	// - numberValue of Scalar kind
128*1c12ee1eSDan Willemsen	// - TypeName of Name kind
129*1c12ee1eSDan Willemsen	str string
130*1c12ee1eSDan Willemsen}
131*1c12ee1eSDan Willemsen
132*1c12ee1eSDan Willemsen// Kind returns the token kind.
133*1c12ee1eSDan Willemsenfunc (t Token) Kind() Kind {
134*1c12ee1eSDan Willemsen	return t.kind
135*1c12ee1eSDan Willemsen}
136*1c12ee1eSDan Willemsen
137*1c12ee1eSDan Willemsen// RawString returns the read value in string.
138*1c12ee1eSDan Willemsenfunc (t Token) RawString() string {
139*1c12ee1eSDan Willemsen	return string(t.raw)
140*1c12ee1eSDan Willemsen}
141*1c12ee1eSDan Willemsen
142*1c12ee1eSDan Willemsen// Pos returns the token position from the input.
143*1c12ee1eSDan Willemsenfunc (t Token) Pos() int {
144*1c12ee1eSDan Willemsen	return t.pos
145*1c12ee1eSDan Willemsen}
146*1c12ee1eSDan Willemsen
147*1c12ee1eSDan Willemsen// NameKind returns IdentName, TypeName or FieldNumber.
148*1c12ee1eSDan Willemsen// It panics if type is not Name.
149*1c12ee1eSDan Willemsenfunc (t Token) NameKind() NameKind {
150*1c12ee1eSDan Willemsen	if t.kind == Name {
151*1c12ee1eSDan Willemsen		return NameKind(t.attrs &^ hasSeparator)
152*1c12ee1eSDan Willemsen	}
153*1c12ee1eSDan Willemsen	panic(fmt.Sprintf("Token is not a Name type: %s", t.kind))
154*1c12ee1eSDan Willemsen}
155*1c12ee1eSDan Willemsen
156*1c12ee1eSDan Willemsen// HasSeparator returns true if the field name is followed by the separator char
157*1c12ee1eSDan Willemsen// ':', else false. It panics if type is not Name.
158*1c12ee1eSDan Willemsenfunc (t Token) HasSeparator() bool {
159*1c12ee1eSDan Willemsen	if t.kind == Name {
160*1c12ee1eSDan Willemsen		return t.attrs&hasSeparator != 0
161*1c12ee1eSDan Willemsen	}
162*1c12ee1eSDan Willemsen	panic(fmt.Sprintf("Token is not a Name type: %s", t.kind))
163*1c12ee1eSDan Willemsen}
164*1c12ee1eSDan Willemsen
165*1c12ee1eSDan Willemsen// IdentName returns the value for IdentName type.
166*1c12ee1eSDan Willemsenfunc (t Token) IdentName() string {
167*1c12ee1eSDan Willemsen	if t.kind == Name && t.attrs&uint8(IdentName) != 0 {
168*1c12ee1eSDan Willemsen		return string(t.raw)
169*1c12ee1eSDan Willemsen	}
170*1c12ee1eSDan Willemsen	panic(fmt.Sprintf("Token is not an IdentName: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))
171*1c12ee1eSDan Willemsen}
172*1c12ee1eSDan Willemsen
173*1c12ee1eSDan Willemsen// TypeName returns the value for TypeName type.
174*1c12ee1eSDan Willemsenfunc (t Token) TypeName() string {
175*1c12ee1eSDan Willemsen	if t.kind == Name && t.attrs&uint8(TypeName) != 0 {
176*1c12ee1eSDan Willemsen		return t.str
177*1c12ee1eSDan Willemsen	}
178*1c12ee1eSDan Willemsen	panic(fmt.Sprintf("Token is not a TypeName: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))
179*1c12ee1eSDan Willemsen}
180*1c12ee1eSDan Willemsen
181*1c12ee1eSDan Willemsen// FieldNumber returns the value for FieldNumber type. It returns a
182*1c12ee1eSDan Willemsen// non-negative int32 value. Caller will still need to validate for the correct
183*1c12ee1eSDan Willemsen// field number range.
184*1c12ee1eSDan Willemsenfunc (t Token) FieldNumber() int32 {
185*1c12ee1eSDan Willemsen	if t.kind != Name || t.attrs&uint8(FieldNumber) == 0 {
186*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("Token is not a FieldNumber: %s:%s", t.kind, NameKind(t.attrs&^hasSeparator)))
187*1c12ee1eSDan Willemsen	}
188*1c12ee1eSDan Willemsen	// Following should not return an error as it had already been called right
189*1c12ee1eSDan Willemsen	// before this Token was constructed.
190*1c12ee1eSDan Willemsen	num, _ := strconv.ParseInt(string(t.raw), 10, 32)
191*1c12ee1eSDan Willemsen	return int32(num)
192*1c12ee1eSDan Willemsen}
193*1c12ee1eSDan Willemsen
194*1c12ee1eSDan Willemsen// String returns the string value for a Scalar type.
195*1c12ee1eSDan Willemsenfunc (t Token) String() (string, bool) {
196*1c12ee1eSDan Willemsen	if t.kind != Scalar || t.attrs != stringValue {
197*1c12ee1eSDan Willemsen		return "", false
198*1c12ee1eSDan Willemsen	}
199*1c12ee1eSDan Willemsen	return t.str, true
200*1c12ee1eSDan Willemsen}
201*1c12ee1eSDan Willemsen
202*1c12ee1eSDan Willemsen// Enum returns the literal value for a Scalar type for use as enum literals.
203*1c12ee1eSDan Willemsenfunc (t Token) Enum() (string, bool) {
204*1c12ee1eSDan Willemsen	if t.kind != Scalar || t.attrs != literalValue || (len(t.raw) > 0 && t.raw[0] == '-') {
205*1c12ee1eSDan Willemsen		return "", false
206*1c12ee1eSDan Willemsen	}
207*1c12ee1eSDan Willemsen	return string(t.raw), true
208*1c12ee1eSDan Willemsen}
209*1c12ee1eSDan Willemsen
210*1c12ee1eSDan Willemsen// Bool returns the bool value for a Scalar type.
211*1c12ee1eSDan Willemsenfunc (t Token) Bool() (bool, bool) {
212*1c12ee1eSDan Willemsen	if t.kind != Scalar {
213*1c12ee1eSDan Willemsen		return false, false
214*1c12ee1eSDan Willemsen	}
215*1c12ee1eSDan Willemsen	switch t.attrs {
216*1c12ee1eSDan Willemsen	case literalValue:
217*1c12ee1eSDan Willemsen		if b, ok := boolLits[string(t.raw)]; ok {
218*1c12ee1eSDan Willemsen			return b, true
219*1c12ee1eSDan Willemsen		}
220*1c12ee1eSDan Willemsen	case numberValue:
221*1c12ee1eSDan Willemsen		// Unsigned integer representation of 0 or 1 is permitted: 00, 0x0, 01,
222*1c12ee1eSDan Willemsen		// 0x1, etc.
223*1c12ee1eSDan Willemsen		n, err := strconv.ParseUint(t.str, 0, 64)
224*1c12ee1eSDan Willemsen		if err == nil {
225*1c12ee1eSDan Willemsen			switch n {
226*1c12ee1eSDan Willemsen			case 0:
227*1c12ee1eSDan Willemsen				return false, true
228*1c12ee1eSDan Willemsen			case 1:
229*1c12ee1eSDan Willemsen				return true, true
230*1c12ee1eSDan Willemsen			}
231*1c12ee1eSDan Willemsen		}
232*1c12ee1eSDan Willemsen	}
233*1c12ee1eSDan Willemsen	return false, false
234*1c12ee1eSDan Willemsen}
235*1c12ee1eSDan Willemsen
236*1c12ee1eSDan Willemsen// These exact boolean literals are the ones supported in C++.
237*1c12ee1eSDan Willemsenvar boolLits = map[string]bool{
238*1c12ee1eSDan Willemsen	"t":     true,
239*1c12ee1eSDan Willemsen	"true":  true,
240*1c12ee1eSDan Willemsen	"True":  true,
241*1c12ee1eSDan Willemsen	"f":     false,
242*1c12ee1eSDan Willemsen	"false": false,
243*1c12ee1eSDan Willemsen	"False": false,
244*1c12ee1eSDan Willemsen}
245*1c12ee1eSDan Willemsen
246*1c12ee1eSDan Willemsen// Uint64 returns the uint64 value for a Scalar type.
247*1c12ee1eSDan Willemsenfunc (t Token) Uint64() (uint64, bool) {
248*1c12ee1eSDan Willemsen	if t.kind != Scalar || t.attrs != numberValue ||
249*1c12ee1eSDan Willemsen		t.numAttrs&isNegative > 0 || t.numAttrs&numFloat > 0 {
250*1c12ee1eSDan Willemsen		return 0, false
251*1c12ee1eSDan Willemsen	}
252*1c12ee1eSDan Willemsen	n, err := strconv.ParseUint(t.str, 0, 64)
253*1c12ee1eSDan Willemsen	if err != nil {
254*1c12ee1eSDan Willemsen		return 0, false
255*1c12ee1eSDan Willemsen	}
256*1c12ee1eSDan Willemsen	return n, true
257*1c12ee1eSDan Willemsen}
258*1c12ee1eSDan Willemsen
259*1c12ee1eSDan Willemsen// Uint32 returns the uint32 value for a Scalar type.
260*1c12ee1eSDan Willemsenfunc (t Token) Uint32() (uint32, bool) {
261*1c12ee1eSDan Willemsen	if t.kind != Scalar || t.attrs != numberValue ||
262*1c12ee1eSDan Willemsen		t.numAttrs&isNegative > 0 || t.numAttrs&numFloat > 0 {
263*1c12ee1eSDan Willemsen		return 0, false
264*1c12ee1eSDan Willemsen	}
265*1c12ee1eSDan Willemsen	n, err := strconv.ParseUint(t.str, 0, 32)
266*1c12ee1eSDan Willemsen	if err != nil {
267*1c12ee1eSDan Willemsen		return 0, false
268*1c12ee1eSDan Willemsen	}
269*1c12ee1eSDan Willemsen	return uint32(n), true
270*1c12ee1eSDan Willemsen}
271*1c12ee1eSDan Willemsen
272*1c12ee1eSDan Willemsen// Int64 returns the int64 value for a Scalar type.
273*1c12ee1eSDan Willemsenfunc (t Token) Int64() (int64, bool) {
274*1c12ee1eSDan Willemsen	if t.kind != Scalar || t.attrs != numberValue || t.numAttrs&numFloat > 0 {
275*1c12ee1eSDan Willemsen		return 0, false
276*1c12ee1eSDan Willemsen	}
277*1c12ee1eSDan Willemsen	if n, err := strconv.ParseInt(t.str, 0, 64); err == nil {
278*1c12ee1eSDan Willemsen		return n, true
279*1c12ee1eSDan Willemsen	}
280*1c12ee1eSDan Willemsen	// C++ accepts large positive hex numbers as negative values.
281*1c12ee1eSDan Willemsen	// This feature is here for proto1 backwards compatibility purposes.
282*1c12ee1eSDan Willemsen	if flags.ProtoLegacy && (t.numAttrs == numHex) {
283*1c12ee1eSDan Willemsen		if n, err := strconv.ParseUint(t.str, 0, 64); err == nil {
284*1c12ee1eSDan Willemsen			return int64(n), true
285*1c12ee1eSDan Willemsen		}
286*1c12ee1eSDan Willemsen	}
287*1c12ee1eSDan Willemsen	return 0, false
288*1c12ee1eSDan Willemsen}
289*1c12ee1eSDan Willemsen
290*1c12ee1eSDan Willemsen// Int32 returns the int32 value for a Scalar type.
291*1c12ee1eSDan Willemsenfunc (t Token) Int32() (int32, bool) {
292*1c12ee1eSDan Willemsen	if t.kind != Scalar || t.attrs != numberValue || t.numAttrs&numFloat > 0 {
293*1c12ee1eSDan Willemsen		return 0, false
294*1c12ee1eSDan Willemsen	}
295*1c12ee1eSDan Willemsen	if n, err := strconv.ParseInt(t.str, 0, 32); err == nil {
296*1c12ee1eSDan Willemsen		return int32(n), true
297*1c12ee1eSDan Willemsen	}
298*1c12ee1eSDan Willemsen	// C++ accepts large positive hex numbers as negative values.
299*1c12ee1eSDan Willemsen	// This feature is here for proto1 backwards compatibility purposes.
300*1c12ee1eSDan Willemsen	if flags.ProtoLegacy && (t.numAttrs == numHex) {
301*1c12ee1eSDan Willemsen		if n, err := strconv.ParseUint(t.str, 0, 32); err == nil {
302*1c12ee1eSDan Willemsen			return int32(n), true
303*1c12ee1eSDan Willemsen		}
304*1c12ee1eSDan Willemsen	}
305*1c12ee1eSDan Willemsen	return 0, false
306*1c12ee1eSDan Willemsen}
307*1c12ee1eSDan Willemsen
308*1c12ee1eSDan Willemsen// Float64 returns the float64 value for a Scalar type.
309*1c12ee1eSDan Willemsenfunc (t Token) Float64() (float64, bool) {
310*1c12ee1eSDan Willemsen	if t.kind != Scalar {
311*1c12ee1eSDan Willemsen		return 0, false
312*1c12ee1eSDan Willemsen	}
313*1c12ee1eSDan Willemsen	switch t.attrs {
314*1c12ee1eSDan Willemsen	case literalValue:
315*1c12ee1eSDan Willemsen		if f, ok := floatLits[strings.ToLower(string(t.raw))]; ok {
316*1c12ee1eSDan Willemsen			return f, true
317*1c12ee1eSDan Willemsen		}
318*1c12ee1eSDan Willemsen	case numberValue:
319*1c12ee1eSDan Willemsen		n, err := strconv.ParseFloat(t.str, 64)
320*1c12ee1eSDan Willemsen		if err == nil {
321*1c12ee1eSDan Willemsen			return n, true
322*1c12ee1eSDan Willemsen		}
323*1c12ee1eSDan Willemsen		nerr := err.(*strconv.NumError)
324*1c12ee1eSDan Willemsen		if nerr.Err == strconv.ErrRange {
325*1c12ee1eSDan Willemsen			return n, true
326*1c12ee1eSDan Willemsen		}
327*1c12ee1eSDan Willemsen	}
328*1c12ee1eSDan Willemsen	return 0, false
329*1c12ee1eSDan Willemsen}
330*1c12ee1eSDan Willemsen
331*1c12ee1eSDan Willemsen// Float32 returns the float32 value for a Scalar type.
332*1c12ee1eSDan Willemsenfunc (t Token) Float32() (float32, bool) {
333*1c12ee1eSDan Willemsen	if t.kind != Scalar {
334*1c12ee1eSDan Willemsen		return 0, false
335*1c12ee1eSDan Willemsen	}
336*1c12ee1eSDan Willemsen	switch t.attrs {
337*1c12ee1eSDan Willemsen	case literalValue:
338*1c12ee1eSDan Willemsen		if f, ok := floatLits[strings.ToLower(string(t.raw))]; ok {
339*1c12ee1eSDan Willemsen			return float32(f), true
340*1c12ee1eSDan Willemsen		}
341*1c12ee1eSDan Willemsen	case numberValue:
342*1c12ee1eSDan Willemsen		n, err := strconv.ParseFloat(t.str, 64)
343*1c12ee1eSDan Willemsen		if err == nil {
344*1c12ee1eSDan Willemsen			// Overflows are treated as (-)infinity.
345*1c12ee1eSDan Willemsen			return float32(n), true
346*1c12ee1eSDan Willemsen		}
347*1c12ee1eSDan Willemsen		nerr := err.(*strconv.NumError)
348*1c12ee1eSDan Willemsen		if nerr.Err == strconv.ErrRange {
349*1c12ee1eSDan Willemsen			return float32(n), true
350*1c12ee1eSDan Willemsen		}
351*1c12ee1eSDan Willemsen	}
352*1c12ee1eSDan Willemsen	return 0, false
353*1c12ee1eSDan Willemsen}
354*1c12ee1eSDan Willemsen
355*1c12ee1eSDan Willemsen// These are the supported float literals which C++ permits case-insensitive
356*1c12ee1eSDan Willemsen// variants of these.
357*1c12ee1eSDan Willemsenvar floatLits = map[string]float64{
358*1c12ee1eSDan Willemsen	"nan":       math.NaN(),
359*1c12ee1eSDan Willemsen	"inf":       math.Inf(1),
360*1c12ee1eSDan Willemsen	"infinity":  math.Inf(1),
361*1c12ee1eSDan Willemsen	"-inf":      math.Inf(-1),
362*1c12ee1eSDan Willemsen	"-infinity": math.Inf(-1),
363*1c12ee1eSDan Willemsen}
364*1c12ee1eSDan Willemsen
365*1c12ee1eSDan Willemsen// TokenEquals returns true if given Tokens are equal, else false.
366*1c12ee1eSDan Willemsenfunc TokenEquals(x, y Token) bool {
367*1c12ee1eSDan Willemsen	return x.kind == y.kind &&
368*1c12ee1eSDan Willemsen		x.attrs == y.attrs &&
369*1c12ee1eSDan Willemsen		x.numAttrs == y.numAttrs &&
370*1c12ee1eSDan Willemsen		x.pos == y.pos &&
371*1c12ee1eSDan Willemsen		bytes.Equal(x.raw, y.raw) &&
372*1c12ee1eSDan Willemsen		x.str == y.str
373*1c12ee1eSDan Willemsen}
374