1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
2// SPDX-FileCopyrightText: 2026 The Project Pterodactyl Developers
3//
4// SPDX-License-Identifier: MPL-2.0
5
6import OrderedCollections
7
8extension Parser {
9
10 struct DelimiterInfo {
11 let left: TokenKind
12 let sep: TokenKind
13 let right: TokenKind
14
15 static var block: DelimiterInfo {
16 DelimiterInfo(left: .blockBegin, sep: .blockSep, right: .blockEnd)
17 }
18
19 static var curly: DelimiterInfo {
20 DelimiterInfo(left: .punctuation(.lbrace), sep: .punctuation(.semicolon), right: .punctuation(.rbrace))
21 }
22 }
23
24 mutating func open(_ delim: DelimiterInfo) -> Bool {
25 guard isAt(kind: delim.left) else { return false }
26 expect(kind: delim.left)
27 _ = eatSeparators(delim)
28 return true
29 }
30
31 /// A liberal parser that allows unlimited dead delimiters separating only trivia.
32 mutating func eatSeparators(_ delim: DelimiterInfo) -> Bool {
33 eatTrivia()
34 var status = false
35 while eat(kind: delim.sep) {
36 status = true
37 eatTrivia()
38 }
39 return status
40 }
41
42 mutating func close(_ delim: DelimiterInfo) {
43 eatTrivia()
44 expect(kind: delim.right)
45 }
46
47 mutating func declLhs() {
48 var handle = structure(kind: .declLhs)
49 defer { handle.close() }
50
51 problemPattern()
52 }
53
54 mutating func problemPattern() {
55 var appHandle = structure(kind: .spine)
56 defer { appHandle.close() }
57
58 do {
59 var handle = structure(kind: .identifier)
60 defer { handle.close() }
61 expect(kind: .identifier, metadata: TokenMetadata(semanticTokenType: .function))
62 }
63
64 eatTrivia()
65
66 var isNonempty = false
67 while trySpineFrame() {
68 eatTrivia()
69 isNonempty = true
70 }
71
72 if !isNonempty { appHandle.cancel() }
73 }
74
75 struct Scanner {
76 let tokens: [Token]
77 var position: Int
78
79 var currentToken: Token { tokens[position] }
80
81 mutating func eat(kindSatisfying predicate: (TokenKind) -> Bool) -> Bool {
82 guard position < tokens.count, predicate(currentToken.kind) else { return false }
83 position += 1
84 return true
85 }
86
87 mutating func eat(kind: TokenKind) -> Bool {
88 eat(kindSatisfying: { $0 == kind })
89 }
90
91 mutating func eatTrivia() {
92 while position < tokens.count, currentToken.kind.isTrivia { position += 1 }
93 }
94 }
95
96
97 var isAtTypedBinder: Bool {
98 var scanner = Scanner(tokens: tokens, position: self.position)
99 guard scanner.eat(kind: .punctuation(.lparen)) else { return false }
100 scanner.eatTrivia()
101 guard scanner.eat(kind: .identifier) else { return false }
102 scanner.eatTrivia()
103 guard scanner.eat(kind: .punctuation(.colon)) else { return false }
104 return true
105 }
106
107 mutating func typedBinder() {
108 var handle = structure(kind: .typedBinder)
109 defer { handle.close() }
110
111 expect(kind: .punctuation(.lparen))
112 eatTrivia()
113 expect(kind: .identifier)
114 eatTrivia()
115 expect(kind: .punctuation(.colon))
116 eatTrivia()
117 expression()
118 eatTrivia()
119 expect(kind: .punctuation(.rparen))
120 }
121
122 mutating func tryDepFunType() -> Bool {
123 guard isAtTypedBinder else { return false }
124
125 var handle = structure(kind: .depFunType)
126 defer { handle.close() }
127
128 while isAtTypedBinder {
129 typedBinder()
130 eatTrivia()
131 }
132
133 expect(kind: .punctuation(.rightArrow), metadata: TokenMetadata(semanticTokenType: .keyword))
134 eatTrivia()
135 expression()
136
137 return true
138 }
139
140 mutating func tryRecordItem() -> Bool {
141 guard isAt(kind: .identifier) else { return false }
142 var handle = structure()
143 defer { handle.close() }
144
145 expect(kind: .identifier)
146 eatTrivia()
147
148 let choices: OrderedDictionary<TokenKind, (TokenMetadata?, RecordItemKind)> = [
149 .punctuation(.colon): (TokenMetadata(semanticTokenType: .keyword), .spec),
150 .punctuation(.doubleRightArrow): (TokenMetadata(semanticTokenType: .keyword), .impl)
151 ]
152
153 if let kind = expect(choices: choices) {
154 handle.kind = .recordItem(kind: kind)
155 eatTrivia()
156 expression()
157 } else {
158 handle.cancel()
159 }
160
161 return true
162 }
163
164 mutating func tryRecord() -> Bool {
165 var handle = structure(kind: .record)
166 defer { handle.close() }
167
168 let delim = DelimiterInfo.curly
169 guard open(delim) else {
170 handle.cancel()
171 return false
172 }
173 defer { close(delim) }
174
175 while true {
176 _ = tryRecordItem()
177 guard eatSeparators(delim) else { break }
178 }
179 return true
180 }
181
182 mutating func tryReflExpression() -> Bool {
183 guard isAt(kind: .keyword(.refl)) else { return false }
184
185 var handle = structure(kind: .refl)
186 defer { handle.close() }
187
188 expect(kind: .keyword(.refl), metadata: TokenMetadata(semanticTokenType: .keyword))
189 return true
190 }
191
192 mutating func universeCodesExpression() -> Bool {
193 let kind = TokenKind.keyword(.type)
194 guard isAt(kind: kind) else { return false }
195
196 var handle = structure(kind: .universeCodes)
197 defer { handle.close() }
198
199 expect(kind: kind, metadata: TokenMetadata(semanticTokenType: .type)) // TODO: is this the right semantic token type?
200
201 return true
202 }
203
204 mutating func holeExpression() -> Bool {
205 let kind = TokenKind.punctuation(.questionMark)
206 guard isAt(kind: kind) else { return false }
207
208 var handle = structure(kind: .hole)
209 defer { handle.close() }
210
211 expect(kind: kind, metadata: TokenMetadata(semanticTokenType: .comment, semanticTokenModifiers: [.abstract]))
212
213 return true
214 }
215
216 mutating func identifierExpression() -> Bool {
217 guard isAt(kind: .identifier) else { return false }
218 var handle = structure(kind: .identifier)
219 defer { handle.close() }
220 expect(kind: .identifier)
221 return true
222 }
223
224 mutating func parenthesisedExpression() -> Bool {
225 guard isAt(kind: .punctuation(.lparen)) else { return false }
226 expect(kind: .punctuation(.lparen))
227 eatTrivia()
228 expression()
229 eatTrivia()
230 expect(kind: .punctuation(.rparen))
231 return true
232 }
233
234 mutating func tryAppFrame() -> Bool {
235 var handle = structure(kind: .appFrame)
236 defer { handle.close() }
237
238 guard tryAtomicExpression() else {
239 handle.cancel()
240 return false
241 }
242
243 return true
244 }
245
246 mutating func tryProjFrame() -> Bool {
247 guard isAt(kind: .punctuation(.dot)) else { return false }
248
249 var handle = structure(kind: .projFrame)
250 defer { handle.close() }
251
252 expect(kind: .punctuation(.dot))
253 expect(kind: .identifier)
254
255 return true
256 }
257
258 mutating func trySpineFrame() -> Bool {
259 tryAppFrame() || tryProjFrame()
260 }
261
262 mutating func trySpineOrIdExpression() -> Bool {
263 var handle = structure()
264 defer { handle.close() }
265
266 guard tryAtomicExpression() else {
267 handle.cancel()
268 return false
269 }
270
271 eatTrivia()
272
273 if isAt(kind: .punctuation(.equal)) {
274 handle.kind = .idType
275 expect(kind: .punctuation(.equal), metadata: TokenMetadata(semanticTokenType: .operator))
276 eatTrivia()
277 atomicExpression()
278 return true
279 } else {
280 handle.kind = .spine
281
282 var isNonempty = false
283 while trySpineFrame() {
284 eatTrivia()
285 isNonempty = true
286 }
287
288 if !isNonempty { handle.cancel() }
289
290 return true
291 }
292 }
293
294 mutating func tryAtomicExpression() -> Bool {
295 return holeExpression()
296 || universeCodesExpression()
297 || identifierExpression()
298 || parenthesisedExpression()
299 || tryRecord()
300 || tryReflExpression()
301 }
302
303 mutating func atomicExpression() {
304 guard tryAtomicExpression() else {
305 return advance(error: "Expected atomic expression")
306 }
307 }
308
309 mutating func tryExpression() -> Bool {
310 if tryDepFunType() { return true }
311
312 var handle = structure()
313 defer { handle.close() }
314
315 guard trySpineOrIdExpression() else {
316 handle.cancel()
317 return false
318 }
319
320 var scanner = Scanner(tokens: tokens, position: position)
321 scanner.eatTrivia()
322 if scanner.eat(kind: .punctuation(.rightArrow)) {
323 handle.kind = .funType
324 eatTrivia()
325 expect(kind: .punctuation(.rightArrow), metadata: TokenMetadata(semanticTokenType: .keyword))
326 eatTrivia()
327 expression()
328 } else {
329 handle.cancel()
330 }
331
332 return true
333 }
334
335 mutating func expression() {
336 guard tryExpression() else {
337 return advance(error: "Expected expression")
338 }
339 }
340
341 mutating func declRhs(declKind: SyntaxTreeKind) {
342 var handle = structure(kind: .declRhs)
343 defer { handle.close() }
344
345 switch declKind {
346 case .claimDecl, .defineDecl:
347 _ = tryExpression()
348 case .refineDecl:
349 _ = eat(kind: .identifier, metadata: TokenMetadata(semanticTokenType: .keyword)) // TODO
350 default:
351 return
352 }
353 }
354
355 mutating func tryLeafDecl() -> Bool {
356 guard isAt(kind: .identifier) else { return false }
357
358 var handle = structure()
359 defer { handle.close() }
360
361 declLhs()
362 eatTrivia()
363
364 switch currentToken.kind {
365 case .punctuation(.doubleLeftArrow):
366 advance(metadata: TokenMetadata(semanticTokenType: .keyword))
367 handle.kind = .refineDecl
368 case .punctuation(.doubleRightArrow):
369 advance(metadata: TokenMetadata(semanticTokenType: .keyword))
370 handle.kind = .defineDecl
371 case .punctuation(.colon):
372 advance(metadata: TokenMetadata(semanticTokenType: .keyword))
373 handle.kind = .claimDecl
374 default:
375 handle.kind = .probeDecl
376 }
377
378 eatTrivia()
379 declRhs(declKind: handle.kind)
380
381 return true
382 }
383
384 mutating func tryDecl() -> Bool {
385 return tryTheory() || tryLeafDecl()
386 }
387
388 mutating func keyword(_ keyword: Keyword) {
389 expect(kind: .keyword(keyword), metadata: TokenMetadata(semanticTokenType: .keyword))
390 }
391
392 mutating func theoryName() {
393 var handle = structure(kind: .theoryName)
394 defer { handle.close() }
395 expect(kind: .identifier, metadata: TokenMetadata(semanticTokenType: .interface))
396 }
397
398 mutating func theoryBlock() {
399 var handle = recoveryStack.push([.blockSep, .blockEnd])
400 defer { handle.close() }
401
402 let delim = DelimiterInfo.block
403
404 guard open(delim) else { return }
405 defer { close(delim) }
406
407 while true {
408 _ = tryDecl()
409 guard eatSeparators(delim) else { break }
410 }
411 }
412
413 mutating func tryTheory() -> Bool {
414 guard isAt(kind: .keyword(.theory)) else { return false }
415
416 var handle = structure(kind: .theory, metadata: SyntaxTreeMetadata(delimitedFoldingRangeKind: .region))
417 defer { handle.close() }
418
419 eatTrivia()
420 keyword(.theory)
421 eatTrivia()
422 theoryName()
423 eatTrivia()
424 keyword(.where)
425 eatTrivia()
426 theoryBlock()
427
428 return true
429 }
430
431 mutating func importName() {
432 var handle = structure(kind: .importName)
433 defer { handle.close() }
434 expect(kind: .identifier)
435 }
436
437 mutating func importDecl() -> Bool {
438 guard isAt(kind: .keyword(.import)) else { return false }
439
440 var handle = structure(kind: .import)
441 defer { handle.close() }
442
443 keyword(.import)
444 eatTrivia()
445 importName()
446
447 return true
448 }
449
450 mutating func tryDocumentItem() -> Bool {
451 if importDecl() { return true }
452 return tryDecl()
453 }
454
455 mutating func documentBlock() {
456 var handle = recoveryStack.push([.blockSep, .blockEnd])
457 defer { handle.close() }
458
459 let delim = DelimiterInfo.block
460
461 guard open(delim) else { return }
462 defer { close(delim) }
463
464 while true {
465 _ = tryDocumentItem()
466 guard eatSeparators(delim) else { break }
467 }
468 }
469
470 public mutating func document() {
471 var handle = structure(kind: .document)
472 defer { handle.close() }
473
474 eatTrivia()
475 documentBlock()
476 eatTrivia()
477
478 expect(kind: .eof)
479 }
480}