1import Foundation 2 3public struct SyntaxTree: Codable, Sendable { 4 public let kind: SyntaxTreeKind 5 public let metadata: SyntaxTreeMetadata? 6 public let children: [Child] 7 public let utf16Length: Int 8 9 public enum Child: Codable, Sendable { 10 case token(Token, metadata: TokenMetadata?) 11 case tree(SyntaxTree) 12 } 13 14 public init(kind: SyntaxTreeKind, metadata: SyntaxTreeMetadata?, children: [SyntaxTree.Child]) { 15 self.kind = kind 16 self.metadata = metadata 17 self.children = children 18 self.utf16Length = children.reduce(0) { length, child in 19 length + child.utf16Length 20 } 21 } 22} 23 24extension SyntaxTree { 25 public var text: String { 26 children.map(\.text).joined() 27 } 28} 29 30extension SyntaxTree.Child { 31 var text: String { 32 switch self { 33 case let .token(tok, _): tok.text 34 case let .tree(tree): tree.text 35 } 36 } 37 38 var utf16Length: Int { 39 switch self { 40 case let .token(token, _): token.utf16Length 41 case let .tree(tree): tree.utf16Length 42 } 43 } 44 45 var children: [Self] { 46 switch self { 47 case .token: [] 48 case let .tree(tree): tree.children 49 } 50 } 51} 52 53extension SyntaxTree: CustomStringConvertible { 54 public var description: String { 55 prettyPrint() 56 } 57 58 /// Pretty-print the tree with indentation. 59 func prettyPrint(indent: String = "") -> String { 60 var result = "\(indent)\(kind)" 61 for child in children { 62 switch child { 63 case .token(let token, _): 64 result += "\n\(indent) \(token.kind): \(token.text.replacingOccurrences(of: "\n", with: "\\n"))" 65 case .tree(let subtree): 66 result += "\n" + subtree.prettyPrint(indent: indent + " ") 67 } 68 } 69 return result 70 } 71}