extension PureYAML.Parsing.Parser { func parseEvents(_ yaml: String) throws -> [PureYAML.Parsing.Event] { let events: [PureYAML.Parsing.Event] do { var parser = try PureYAML.Parsing.LibYAML.Parser(yaml) events = try parser.parse().map { $0.bumpingMark() } } catch let error as PureYAML.Parsing.LibYAML.ScannerError { throw PureYAML.Parsing.ParseError(translating: error) } catch let error as PureYAML.Parsing.LibYAML.ParserError { throw PureYAML.Parsing.ParseError(translating: error) } try enforceNestingLimit(events) return events } /// The deepest collection nesting the value/event composers will build. The /// ported parser produces events iteratively without recursion, but the /// composers, equality, hashing, and `Model/Value` teardown all recurse with /// the nesting depth, so the event stream is bounded here before any recursive /// consumer runs. 64 accepts every realistic document yet rejects pathological /// input well before it can overflow the stack. static var maxNestingDepth: Int { 64 } /// Reject an event stream that nests collections past ``maxNestingDepth`` with /// a ``ParseError/nestingTooDeep(line:column:)`` so deeply nested input fails /// cleanly instead of overflowing a recursive consumer's stack. private func enforceNestingLimit(_ events: [PureYAML.Parsing.Event]) throws { var depth = 0 for event in events { switch event { case .sequenceStart, .mappingStart: depth += 1 if depth > Self.maxNestingDepth { throw PureYAML.Parsing.ParseError.nestingTooDeep(line: event.mark.line, column: event.mark.column) } case .sequenceEnd, .mappingEnd: depth -= 1 default: break } } } func parseStreaming(_ yaml: String) throws -> PureYAML.Model.Value { var composer = PureYAML.Parsing.EventStreamComposer( scalarParser: self, mode: .singleDocument, ) for event in try parseEvents(yaml) { try composer.consume(event) } return try composer.composedValue() } func parseStreamStreaming(_ yaml: String) throws -> [PureYAML.Stream.Document] { var composer = PureYAML.Parsing.EventStreamComposer( scalarParser: self, mode: .stream, ) for event in try parseEvents(yaml) { try composer.consume(event) } return try composer.composedStream() } func parseLocatedStreaming(_ yaml: String) throws -> PureYAML.Model.LocatedValue { var composer = PureYAML.Parsing.EventStreamComposer( scalarParser: self, mode: .singleDocument, tracksLocations: true, ) for event in try parseEvents(yaml) { try composer.consume(event) } return try composer.composedLocated() } func parseStreamLocatedStreaming(_ yaml: String) throws -> [PureYAML.Model.LocatedValue] { var composer = PureYAML.Parsing.EventStreamComposer( scalarParser: self, mode: .stream, tracksLocations: true, ) for event in try parseEvents(yaml) { try composer.consume(event) } return try composer.composedLocatedStream() } }