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