PureYAML/Sources/Parsing/Parser.Events.swift
Mihaela Mihaljevic 0588996506 feat(parsing): run the whole library on the ported engine
Routes the value and stream APIs through the ported scanner+parser (the
event API already was), so PureYAML now parses entirely on the libyaml
port. Adds the features needed to match and exceed the previous engine:
JSON UTF-16 surrogate-pair \u escapes, bare documents after an explicit
`...`, reserved-directive handling that still requires a following `---`,
and a 64-level nesting bound enforced on the event stream so deeply nested
input fails with nestingTooDeep instead of overflowing a recursive
consumer. Parser errors are translated to the diagnostic-aware ParseError,
recovering precise codes where identifiable and a readable malformed
fallback otherwise; error-reporting fixtures are rebased onto the port.

Canonical event conformance: 268 -> 271 of 308 (7Z25, HWV9, QT73).
393 tests pass.
2026-06-24 18:02:22 +02:00

68 lines
2.6 KiB
Swift

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()
}
}