1package toml
2
3import (
4	"fmt"
5	"strconv"
6	"unicode"
7)
8
9// Define tokens
10type tokenType int
11
12const (
13	eof = -(iota + 1)
14)
15
16const (
17	tokenError tokenType = iota
18	tokenEOF
19	tokenComment
20	tokenKey
21	tokenString
22	tokenInteger
23	tokenTrue
24	tokenFalse
25	tokenFloat
26	tokenInf
27	tokenNan
28	tokenEqual
29	tokenLeftBracket
30	tokenRightBracket
31	tokenLeftCurlyBrace
32	tokenRightCurlyBrace
33	tokenLeftParen
34	tokenRightParen
35	tokenDoubleLeftBracket
36	tokenDoubleRightBracket
37	tokenDate
38	tokenKeyGroup
39	tokenKeyGroupArray
40	tokenComma
41	tokenColon
42	tokenDollar
43	tokenStar
44	tokenQuestion
45	tokenDot
46	tokenDotDot
47	tokenEOL
48)
49
50var tokenTypeNames = []string{
51	"Error",
52	"EOF",
53	"Comment",
54	"Key",
55	"String",
56	"Integer",
57	"True",
58	"False",
59	"Float",
60	"Inf",
61	"NaN",
62	"=",
63	"[",
64	"]",
65	"{",
66	"}",
67	"(",
68	")",
69	"]]",
70	"[[",
71	"Date",
72	"KeyGroup",
73	"KeyGroupArray",
74	",",
75	":",
76	"$",
77	"*",
78	"?",
79	".",
80	"..",
81	"EOL",
82}
83
84type token struct {
85	Position
86	typ tokenType
87	val string
88}
89
90func (tt tokenType) String() string {
91	idx := int(tt)
92	if idx < len(tokenTypeNames) {
93		return tokenTypeNames[idx]
94	}
95	return "Unknown"
96}
97
98func (t token) Int() int {
99	if result, err := strconv.Atoi(t.val); err != nil {
100		panic(err)
101	} else {
102		return result
103	}
104}
105
106func (t token) String() string {
107	switch t.typ {
108	case tokenEOF:
109		return "EOF"
110	case tokenError:
111		return t.val
112	}
113
114	return fmt.Sprintf("%q", t.val)
115}
116
117func isSpace(r rune) bool {
118	return r == ' ' || r == '\t'
119}
120
121func isAlphanumeric(r rune) bool {
122	return unicode.IsLetter(r) || r == '_'
123}
124
125func isKeyChar(r rune) bool {
126	// Keys start with the first character that isn't whitespace or [ and end
127	// with the last non-whitespace character before the equals sign. Keys
128	// cannot contain a # character."
129	return !(r == '\r' || r == '\n' || r == eof || r == '=')
130}
131
132func isKeyStartChar(r rune) bool {
133	return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '[')
134}
135
136func isDigit(r rune) bool {
137	return unicode.IsNumber(r)
138}
139
140func isHexDigit(r rune) bool {
141	return isDigit(r) ||
142		(r >= 'a' && r <= 'f') ||
143		(r >= 'A' && r <= 'F')
144}
145