at main 1.7 kB view raw
1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers 2// 3// SPDX-License-Identifier: MPL-2.0 4 5import Foundation 6 7public struct SyntaxTreeBuilder { 8 private enum Event: Equatable { 9 case open(kind: SyntaxTreeKind, metadata: SyntaxTreeMetadata?) 10 case close 11 case advance(token: Token, metadata: TokenMetadata?) 12 } 13 14 public struct MarkOpened { 15 internal let index: Int 16 } 17 18 private var events: [Event] = [] 19 20 public mutating func advance(token: Token, metadata: TokenMetadata?) { 21 events.append(.advance(token: token, metadata: metadata)) 22 } 23 24 public mutating func open() -> MarkOpened { 25 let mark = MarkOpened(index: events.count) 26 events.append(.open(kind: .error, metadata: nil)) 27 return mark 28 } 29 30 public mutating func close(mark: MarkOpened, kind: SyntaxTreeKind, metadata: SyntaxTreeMetadata?) { 31 events[mark.index] = .open(kind: kind, metadata: metadata) 32 events.append(.close) 33 } 34 35 public var tree: SyntaxTree { 36 var events = events 37 var stack: [SyntaxTree.MutableTree] = [] 38 39 precondition(events.popLast() == .close) 40 41 for event in events { 42 switch event { 43 case .open(let kind, let metadata): 44 stack.append(SyntaxTree.MutableTree(kind: kind, metadata: metadata, children: [])) 45 case .close: 46 let tree = stack.popLast()! 47 stack.modifyLast { last in 48 last.children.append(.tree(tree.tree)) 49 } 50 case .advance(let token, let metadata): 51 stack.modifyLast { last in 52 last.children.append(.token(token, metadata: metadata)) 53 } 54 } 55 } 56 57 assert(stack.count == 1) 58 return stack.popLast()!.tree 59 } 60} 61 62 63extension Array { 64 fileprivate mutating func modifyLast(_ modifier: (inout Element) -> Void) { 65 if var last = popLast() { 66 modifier(&last) 67 append(last) 68 } 69 } 70}