···
+
// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers
+
// SPDX-License-Identifier: MPL-2.0
+
enum Event: Equatable {
+
case open(kind: SyntaxTreeKind)
+
public struct MarkOpened {
+
internal let index: Int
+
public init(source: String, tokens: [Token]) {
+
public private(set) var diagnostics: [Diagnostic] = []
+
private var fuel: Int = 0
+
private var position: Int = 0
+
private var events: [Event] = []
+
private var absoluteUtf16Offset: Int = 0
+
public var absoluteRangeAtCursor: Range<Int> {
+
return absoluteUtf16Offset..<absoluteUtf16Offset
+
public var absoluteRangeOfCurrentToken: Range<Int> {
+
return absoluteUtf16Offset..<absoluteUtf16Offset + currentToken.utf16Length
+
public var isEndOfFile: Bool {
+
position == tokens.count
+
public var currentToken: Token {
+
if tokens.indices.contains(position) {
+
return tokens[position]
+
public func isAt(kind: TokenKind) -> Bool {
+
currentToken.kind == kind
+
public func isAt(kindSatisfying predicate: (TokenKind) -> Bool) -> Bool {
+
return predicate(currentToken.kind)
+
public mutating func open() -> MarkOpened {
+
let mark = MarkOpened(index: events.count)
+
events.append(.open(kind: .error))
+
public mutating func close(mark: MarkOpened, kind: SyntaxTreeKind) {
+
events[mark.index] = .open(kind: kind)
+
public mutating func advance() {
+
precondition(!isEndOfFile)
+
events.append(.advance)
+
absoluteUtf16Offset += currentToken.utf16Length
+
public mutating func advance(error: String?) {
+
let diagnostic = Diagnostic(
+
absoluteRange: absoluteRangeOfCurrentToken
+
diagnostics.append(diagnostic)
+
close(mark: mark, kind: .error)
+
public mutating func lookahead(_ k: Int) -> TokenKind? {
+
precondition(fuel > 0, "Parser is stuck!")
+
let index = position + k
+
guard tokens.indices.contains(index) else { return nil }
+
return tokens[index].kind
+
public mutating func eat(kindSatisfying predicate: (TokenKind) -> Bool) -> Bool {
+
guard !isEndOfFile && isAt(kindSatisfying: predicate) else { return false }
+
public mutating func eat(kind: TokenKind) -> Bool {
+
public mutating func expect(kind: TokenKind, error: String? = nil) {
+
if eat(kind: kind) { return }
+
let diagnostic = Diagnostic(
+
message: error ?? "Expected \(kind) but got \(currentToken.kind): `\(currentToken.text)`",
+
absoluteRange: absoluteRangeAtCursor
+
diagnostics.append(diagnostic)
+
public var tree: SyntaxTree {
+
var stack: [SyntaxTree] = []
+
precondition(events.popLast() == .close)
+
stack.append(SyntaxTree(kind: kind, children: []))
+
let tree = stack.popLast()!
+
stack.modifyLast { last in
+
last.children.append(.tree(tree))
+
let token = tokens[cursor]
+
stack.modifyLast { last in
+
last.children.append(.token(token))
+
assert(stack.count == 1)
+
return stack.popLast()!
+
fileprivate mutating func modifyLast(_ modifier: (inout Element) -> Void) {
+
if var last = popLast() {