at main 2.4 kB view raw
1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers 2// 3// SPDX-License-Identifier: MPL-2.0 4 5import Foundation 6 7/// This is a green tree in the sense of Roslyn. 8public struct SyntaxTree: Codable, Sendable { 9 public let kind: SyntaxTreeKind 10 public let metadata: SyntaxTreeMetadata? 11 public let children: [Child] 12 public let utf16Length: Int 13 14 public enum Child: Codable, Sendable { 15 case token(Token, metadata: TokenMetadata?) 16 case tree(SyntaxTree) 17 } 18 19 public init(kind: SyntaxTreeKind, metadata: SyntaxTreeMetadata? = nil, children: [SyntaxTree.Child]) { 20 self.kind = kind 21 self.metadata = metadata 22 self.children = children 23 self.utf16Length = children.reduce(0) { length, child in 24 length + child.utf16Length 25 } 26 } 27} 28 29extension SyntaxTree { 30 /// A mutable version of ``SyntaxTree`` that does not keep track of textual length, for use when constructing trees. 31 public struct MutableTree { 32 public var kind: SyntaxTreeKind 33 public var metadata: SyntaxTreeMetadata? 34 public var children: [Child] 35 36 var tree: SyntaxTree { 37 SyntaxTree(kind: kind, metadata: metadata, children: children) 38 } 39 } 40} 41 42extension SyntaxTree { 43 public var text: String { 44 children.map(\.text).joined() 45 } 46} 47 48extension SyntaxTree.Child { 49 public var text: String { 50 switch self { 51 case let .token(tok, _): tok.text 52 case let .tree(tree): tree.text 53 } 54 } 55 56 public var tree: SyntaxTree? { 57 switch self { 58 case let .tree(tree): tree 59 default: nil 60 } 61 } 62 63 var token: (Token, TokenMetadata?)? { 64 switch self { 65 case let .token(token, metadata): (token, metadata) 66 default: nil 67 } 68 } 69 70 var utf16Length: Int { 71 switch self { 72 case let .token(token, _): token.utf16Length 73 case let .tree(tree): tree.utf16Length 74 } 75 } 76 77 var children: [Self] { 78 switch self { 79 case .token: [] 80 case let .tree(tree): tree.children 81 } 82 } 83} 84 85extension SyntaxTree: CustomStringConvertible { 86 public var description: String { 87 prettyPrint() 88 } 89 90 /// Pretty-print the tree with indentation. 91 func prettyPrint(indent: String = "") -> String { 92 var result = "\(indent)\(kind)" 93 for child in children { 94 switch child { 95 case .token(let token, _): 96 result += "\n\(indent) \(token.kind): \(token.text.replacingOccurrences(of: "\n", with: "\\n"))" 97 case .tree(let subtree): 98 result += "\n" + subtree.prettyPrint(indent: indent + " ") 99 } 100 } 101 return result 102 } 103}