1 package tracker
2
3 import (
4 "bytes"
5 "fmt"
6 "sync"
7
8 "github.com/pelletier/go-toml/v2/unstable"
9 )
10
11 type keyKind uint8
12
13 const (
14 invalidKind keyKind = iota
15 valueKind
16 tableKind
17 arrayTableKind
18 )
19
20 func (k keyKind) String() string {
21 switch k {
22 case invalidKind:
23 return "invalid"
24 case valueKind:
25 return "value"
26 case tableKind:
27 return "table"
28 case arrayTableKind:
29 return "array table"
30 }
31 panic("missing keyKind string mapping")
32 }
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 type SeenTracker struct {
56 entries []entry
57 currentIdx int
58 }
59
60 var pool sync.Pool
61
62 func (s *SeenTracker) reset() {
63
64 s.currentIdx = 0
65 if len(s.entries) == 0 {
66 s.entries = make([]entry, 1, 2)
67 } else {
68 s.entries = s.entries[:1]
69 }
70 s.entries[0].child = -1
71 s.entries[0].next = -1
72 }
73
74 type entry struct {
75
76 child int
77 next int
78
79 name []byte
80 kind keyKind
81 explicit bool
82 kv bool
83 }
84
85
86
87 func (s *SeenTracker) find(parentIdx int, k []byte) int {
88 for i := s.entries[parentIdx].child; i >= 0; i = s.entries[i].next {
89 if bytes.Equal(s.entries[i].name, k) {
90 return i
91 }
92 }
93 return -1
94 }
95
96
97 func (s *SeenTracker) clear(idx int) {
98 if idx >= len(s.entries) {
99 return
100 }
101
102 for i := s.entries[idx].child; i >= 0; {
103 next := s.entries[i].next
104 n := s.entries[0].next
105 s.entries[0].next = i
106 s.entries[i].next = n
107 s.entries[i].name = nil
108 s.clear(i)
109 i = next
110 }
111
112 s.entries[idx].child = -1
113 }
114
115 func (s *SeenTracker) create(parentIdx int, name []byte, kind keyKind, explicit bool, kv bool) int {
116 e := entry{
117 child: -1,
118 next: s.entries[parentIdx].child,
119
120 name: name,
121 kind: kind,
122 explicit: explicit,
123 kv: kv,
124 }
125 var idx int
126 if s.entries[0].next >= 0 {
127 idx = s.entries[0].next
128 s.entries[0].next = s.entries[idx].next
129 s.entries[idx] = e
130 } else {
131 idx = len(s.entries)
132 s.entries = append(s.entries, e)
133 }
134
135 s.entries[parentIdx].child = idx
136
137 return idx
138 }
139
140 func (s *SeenTracker) setExplicitFlag(parentIdx int) {
141 for i := s.entries[parentIdx].child; i >= 0; i = s.entries[i].next {
142 if s.entries[i].kv {
143 s.entries[i].explicit = true
144 s.entries[i].kv = false
145 }
146 s.setExplicitFlag(i)
147 }
148 }
149
150
151
152
153 func (s *SeenTracker) CheckExpression(node *unstable.Node) error {
154 if s.entries == nil {
155 s.reset()
156 }
157 switch node.Kind {
158 case unstable.KeyValue:
159 return s.checkKeyValue(node)
160 case unstable.Table:
161 return s.checkTable(node)
162 case unstable.ArrayTable:
163 return s.checkArrayTable(node)
164 default:
165 panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
166 }
167 }
168
169 func (s *SeenTracker) checkTable(node *unstable.Node) error {
170 if s.currentIdx >= 0 {
171 s.setExplicitFlag(s.currentIdx)
172 }
173
174 it := node.Key()
175
176 parentIdx := 0
177
178
179
180
181 for it.Next() {
182 if it.IsLast() {
183 break
184 }
185
186 k := it.Node().Data
187
188 idx := s.find(parentIdx, k)
189
190 if idx < 0 {
191 idx = s.create(parentIdx, k, tableKind, false, false)
192 } else {
193 entry := s.entries[idx]
194 if entry.kind == valueKind {
195 return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
196 }
197 }
198 parentIdx = idx
199 }
200
201 k := it.Node().Data
202 idx := s.find(parentIdx, k)
203
204 if idx >= 0 {
205 kind := s.entries[idx].kind
206 if kind != tableKind {
207 return fmt.Errorf("toml: key %s should be a table, not a %s", string(k), kind)
208 }
209 if s.entries[idx].explicit {
210 return fmt.Errorf("toml: table %s already exists", string(k))
211 }
212 s.entries[idx].explicit = true
213 } else {
214 idx = s.create(parentIdx, k, tableKind, true, false)
215 }
216
217 s.currentIdx = idx
218
219 return nil
220 }
221
222 func (s *SeenTracker) checkArrayTable(node *unstable.Node) error {
223 if s.currentIdx >= 0 {
224 s.setExplicitFlag(s.currentIdx)
225 }
226
227 it := node.Key()
228
229 parentIdx := 0
230
231 for it.Next() {
232 if it.IsLast() {
233 break
234 }
235
236 k := it.Node().Data
237
238 idx := s.find(parentIdx, k)
239
240 if idx < 0 {
241 idx = s.create(parentIdx, k, tableKind, false, false)
242 } else {
243 entry := s.entries[idx]
244 if entry.kind == valueKind {
245 return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
246 }
247 }
248
249 parentIdx = idx
250 }
251
252 k := it.Node().Data
253 idx := s.find(parentIdx, k)
254
255 if idx >= 0 {
256 kind := s.entries[idx].kind
257 if kind != arrayTableKind {
258 return fmt.Errorf("toml: key %s already exists as a %s, but should be an array table", kind, string(k))
259 }
260 s.clear(idx)
261 } else {
262 idx = s.create(parentIdx, k, arrayTableKind, true, false)
263 }
264
265 s.currentIdx = idx
266
267 return nil
268 }
269
270 func (s *SeenTracker) checkKeyValue(node *unstable.Node) error {
271 parentIdx := s.currentIdx
272 it := node.Key()
273
274 for it.Next() {
275 k := it.Node().Data
276
277 idx := s.find(parentIdx, k)
278
279 if idx < 0 {
280 idx = s.create(parentIdx, k, tableKind, false, true)
281 } else {
282 entry := s.entries[idx]
283 if it.IsLast() {
284 return fmt.Errorf("toml: key %s is already defined", string(k))
285 } else if entry.kind != tableKind {
286 return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
287 } else if entry.explicit {
288 return fmt.Errorf("toml: cannot redefine table %s that has already been explicitly defined", string(k))
289 }
290 }
291
292 parentIdx = idx
293 }
294
295 s.entries[parentIdx].kind = valueKind
296
297 value := node.Value()
298
299 switch value.Kind {
300 case unstable.InlineTable:
301 return s.checkInlineTable(value)
302 case unstable.Array:
303 return s.checkArray(value)
304 }
305
306 return nil
307 }
308
309 func (s *SeenTracker) checkArray(node *unstable.Node) error {
310 it := node.Children()
311 for it.Next() {
312 n := it.Node()
313 switch n.Kind {
314 case unstable.InlineTable:
315 err := s.checkInlineTable(n)
316 if err != nil {
317 return err
318 }
319 case unstable.Array:
320 err := s.checkArray(n)
321 if err != nil {
322 return err
323 }
324 }
325 }
326 return nil
327 }
328
329 func (s *SeenTracker) checkInlineTable(node *unstable.Node) error {
330 if pool.New == nil {
331 pool.New = func() interface{} {
332 return &SeenTracker{}
333 }
334 }
335
336 s = pool.Get().(*SeenTracker)
337 s.reset()
338
339 it := node.Children()
340 for it.Next() {
341 n := it.Node()
342 err := s.checkKeyValue(n)
343 if err != nil {
344 return err
345 }
346 }
347
348
349
350
351
352
353
354 pool.Put(s)
355 return nil
356 }
357
View as plain text