parseEvents now runs on the ported scanner+parser instead of the hand-rolled approximation. Adds 1-based mark conversion at the boundary (the port stays faithfully 0-based internally), translates the port's scanner and parser errors into the diagnostic-aware ParseError with precise codes (unterminatedQuotedString, unterminatedTag, tabIndentation) and a readable malformed fallback, and retargets the canonical event gate to track the port's gap set. The port matches the canonical test.event on 253 of 308 valid cases; the remaining gaps match libyaml's own behaviour and are the targets for surpassing libyaml. Golden event and diagnostic expectations are rebased onto the port where it is faithful or more correct (resolved verbatim tags, libyaml's stream-end marks, reaching the real unterminated quote). 333 tests pass.
134 lines
4.8 KiB
Swift
134 lines
4.8 KiB
Swift
extension PureYAML.Parsing {
|
|
enum Event: Equatable, CustomStringConvertible {
|
|
case streamStart(mark: Mark)
|
|
case streamEnd(mark: Mark)
|
|
case documentStart(explicit: Bool, mark: Mark)
|
|
case documentEnd(explicit: Bool, mark: Mark)
|
|
case sequenceStart(anchor: String?, tag: String?, style: CollectionStyle, mark: Mark)
|
|
case sequenceEnd(mark: Mark)
|
|
case mappingStart(anchor: String?, tag: String?, style: CollectionStyle, mark: Mark)
|
|
case mappingEnd(mark: Mark)
|
|
case scalar(value: String, anchor: String?, tag: String?, style: ScalarStyle, mark: Mark)
|
|
case alias(anchor: String, mark: Mark)
|
|
|
|
var description: String {
|
|
switch self {
|
|
case let .streamStart(mark):
|
|
"streamStart @\(mark)"
|
|
case let .streamEnd(mark):
|
|
"streamEnd @\(mark)"
|
|
case let .documentStart(explicit, mark):
|
|
"documentStart explicit=\(explicit) @\(mark)"
|
|
case let .documentEnd(explicit, mark):
|
|
"documentEnd explicit=\(explicit) @\(mark)"
|
|
case let .sequenceStart(anchor, tag, style, mark):
|
|
"sequenceStart anchor=\(describe(anchor)) tag=\(describe(tag)) style=\(style) @\(mark)"
|
|
case let .sequenceEnd(mark):
|
|
"sequenceEnd @\(mark)"
|
|
case let .mappingStart(anchor, tag, style, mark):
|
|
"mappingStart anchor=\(describe(anchor)) tag=\(describe(tag)) style=\(style) @\(mark)"
|
|
case let .mappingEnd(mark):
|
|
"mappingEnd @\(mark)"
|
|
case let .scalar(value, anchor, tag, style, mark):
|
|
"scalar value=\"\(escape(value))\" anchor=\(describe(anchor)) tag=\(describe(tag)) style=\(style) @\(mark)"
|
|
case let .alias(anchor, mark):
|
|
"alias anchor=\(anchor) @\(mark)"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension PureYAML.Parsing.Event {
|
|
/// Re-emit the event with libyaml's 0-based line/column mark converted to the
|
|
/// package's 1-based convention (the byte index is already 0-based in both).
|
|
func bumpingMark() -> Self {
|
|
let source = mark
|
|
let bumped = PureYAML.Parsing.Mark(line: source.line + 1, column: source.column + 1, index: source.index)
|
|
switch self {
|
|
case .streamStart:
|
|
return .streamStart(mark: bumped)
|
|
case .streamEnd:
|
|
return .streamEnd(mark: bumped)
|
|
case let .documentStart(explicit, _):
|
|
return .documentStart(explicit: explicit, mark: bumped)
|
|
case let .documentEnd(explicit, _):
|
|
return .documentEnd(explicit: explicit, mark: bumped)
|
|
case let .sequenceStart(anchor, tag, style, _):
|
|
return .sequenceStart(anchor: anchor, tag: tag, style: style, mark: bumped)
|
|
case .sequenceEnd:
|
|
return .sequenceEnd(mark: bumped)
|
|
case let .mappingStart(anchor, tag, style, _):
|
|
return .mappingStart(anchor: anchor, tag: tag, style: style, mark: bumped)
|
|
case .mappingEnd:
|
|
return .mappingEnd(mark: bumped)
|
|
case let .scalar(value, anchor, tag, style, _):
|
|
return .scalar(value: value, anchor: anchor, tag: tag, style: style, mark: bumped)
|
|
case let .alias(anchor, _):
|
|
return .alias(anchor: anchor, mark: bumped)
|
|
}
|
|
}
|
|
|
|
var isMappingEnd: Bool {
|
|
if case .mappingEnd = self {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
var isSequenceEnd: Bool {
|
|
if case .sequenceEnd = self {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
var isStreamEnd: Bool {
|
|
if case .streamEnd = self {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
var mark: PureYAML.Parsing.Mark {
|
|
switch self {
|
|
case let .alias(_, mark),
|
|
let .mappingEnd(mark),
|
|
let .mappingStart(_, _, _, mark),
|
|
let .scalar(_, _, _, _, mark),
|
|
let .sequenceEnd(mark),
|
|
let .sequenceStart(_, _, _, mark),
|
|
let .streamEnd(mark),
|
|
let .streamStart(mark):
|
|
mark
|
|
case let .documentEnd(_, mark),
|
|
let .documentStart(_, mark):
|
|
mark
|
|
}
|
|
}
|
|
|
|
private func describe(_ value: String?) -> String {
|
|
value ?? "-"
|
|
}
|
|
|
|
private func escape(_ value: String) -> String {
|
|
var output = ""
|
|
for character in value {
|
|
switch character {
|
|
case "\\":
|
|
output += "\\\\"
|
|
case "\"":
|
|
output += "\\\""
|
|
case "\n":
|
|
output += "\\n"
|
|
case "\r":
|
|
output += "\\r"
|
|
case "\t":
|
|
output += "\\t"
|
|
default:
|
|
output.append(character)
|
|
}
|
|
}
|
|
return output
|
|
}
|
|
}
|