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.
185 lines
8.1 KiB
Swift
185 lines
8.1 KiB
Swift
public extension PureYAML.Parsing {
|
|
/// Parser error with source line information when available.
|
|
enum ParseError: Swift.Error, Equatable, Sendable, CustomStringConvertible {
|
|
case emptyDocument
|
|
case tabIndentation(line: Int)
|
|
case unexpectedIndentation(line: Int)
|
|
case mixedCollectionStyles(line: Int)
|
|
case expectedMappingKey(line: Int)
|
|
case expectedAnchorName(line: Int)
|
|
case expectedAliasName(line: Int)
|
|
case expectedNode(line: Int, column: Int)
|
|
case expectedScalarKey(line: Int, column: Int)
|
|
case incompatibleYAMLDirective(line: Int)
|
|
case directiveWithoutDocument(line: Int)
|
|
case invalidTaggedScalar(tag: String, value: String, line: Int, column: Int)
|
|
case invalidMergeValue(line: Int, column: Int)
|
|
case unterminatedTag(line: Int)
|
|
case unterminatedQuotedString(line: Int)
|
|
case unsupportedDirective(name: String, line: Int)
|
|
case unsupportedMultiDocumentStream(line: Int)
|
|
case undefinedAlias(anchor: String, line: Int, column: Int)
|
|
case unexpectedEvent(expected: String, actual: String, line: Int, column: Int)
|
|
case unexpectedToken(expected: String, actual: String, line: Int, column: Int)
|
|
case nestingTooDeep(line: Int, column: Int)
|
|
case malformed(reason: String, line: Int, column: Int)
|
|
|
|
public var description: String {
|
|
switch self {
|
|
case .emptyDocument:
|
|
"document is empty"
|
|
case let .tabIndentation(line):
|
|
"tabs are not allowed for indentation at line \(line)"
|
|
case let .unexpectedIndentation(line):
|
|
"unexpected indentation at line \(line)"
|
|
case let .mixedCollectionStyles(line):
|
|
"mapping and sequence entries are mixed at line \(line)"
|
|
case let .expectedMappingKey(line):
|
|
"expected a mapping key at line \(line)"
|
|
case let .expectedAnchorName(line):
|
|
"expected an anchor name at line \(line)"
|
|
case let .expectedAliasName(line):
|
|
"expected an alias name at line \(line)"
|
|
case let .expectedNode(line, column):
|
|
"expected a YAML node at line \(line), column \(column)"
|
|
case let .expectedScalarKey(line, column):
|
|
"expected a scalar mapping key at line \(line), column \(column)"
|
|
case let .incompatibleYAMLDirective(line):
|
|
"incompatible YAML directive at line \(line)"
|
|
case let .directiveWithoutDocument(line):
|
|
"directive is not followed by a document start at line \(line)"
|
|
case let .invalidTaggedScalar(tag, value, line, column):
|
|
"invalid scalar '\(value)' for tag '\(tag)' at line \(line), column \(column)"
|
|
case let .invalidMergeValue(line, column):
|
|
"expected merge value to be a mapping or sequence of mappings at line \(line), column \(column)"
|
|
case let .unterminatedTag(line):
|
|
"unterminated tag at line \(line)"
|
|
case let .unterminatedQuotedString(line):
|
|
"unterminated quoted string at line \(line)"
|
|
case let .unsupportedDirective(name, line):
|
|
"unsupported directive '\(name)' at line \(line)"
|
|
case let .unsupportedMultiDocumentStream(line):
|
|
"multi-document streams are not supported at line \(line)"
|
|
case let .undefinedAlias(anchor, line, column):
|
|
"undefined alias '\(anchor)' at line \(line), column \(column)"
|
|
case let .unexpectedEvent(expected, actual, line, column):
|
|
"expected \(expected) at line \(line), column \(column), found \(actual)"
|
|
case let .unexpectedToken(expected, actual, line, column):
|
|
"expected \(expected) at line \(line), column \(column), found \(actual)"
|
|
case let .nestingTooDeep(line, column):
|
|
"nesting is too deep at line \(line), column \(column)"
|
|
case let .malformed(reason, line, column):
|
|
"\(reason) at line \(line), column \(column)"
|
|
}
|
|
}
|
|
|
|
public var diagnosticCode: String {
|
|
switch self {
|
|
case .emptyDocument:
|
|
"emptyDocument"
|
|
case .tabIndentation:
|
|
"tabIndentation"
|
|
case .unexpectedIndentation:
|
|
"unexpectedIndentation"
|
|
case .mixedCollectionStyles:
|
|
"mixedCollectionStyles"
|
|
case .expectedMappingKey:
|
|
"expectedMappingKey"
|
|
case .expectedAnchorName:
|
|
"expectedAnchorName"
|
|
case .expectedAliasName:
|
|
"expectedAliasName"
|
|
case .expectedNode:
|
|
"expectedNode"
|
|
case .expectedScalarKey:
|
|
"expectedScalarKey"
|
|
case .incompatibleYAMLDirective:
|
|
"incompatibleYAMLDirective"
|
|
case .directiveWithoutDocument:
|
|
"directiveWithoutDocument"
|
|
case .invalidTaggedScalar:
|
|
"invalidTaggedScalar"
|
|
case .invalidMergeValue:
|
|
"invalidMergeValue"
|
|
case .unterminatedTag:
|
|
"unterminatedTag"
|
|
case .unterminatedQuotedString:
|
|
"unterminatedQuotedString"
|
|
case .unsupportedDirective:
|
|
"unsupportedDirective"
|
|
case .unsupportedMultiDocumentStream:
|
|
"unsupportedMultiDocumentStream"
|
|
case .undefinedAlias:
|
|
"undefinedAlias"
|
|
case .unexpectedEvent:
|
|
"unexpectedEvent"
|
|
case .unexpectedToken:
|
|
"unexpectedToken"
|
|
case .nestingTooDeep:
|
|
"nestingTooDeep"
|
|
case .malformed:
|
|
"malformed"
|
|
}
|
|
}
|
|
|
|
public var sourceLine: Int? {
|
|
switch self {
|
|
case .emptyDocument:
|
|
nil
|
|
case let .tabIndentation(line),
|
|
let .unexpectedIndentation(line),
|
|
let .mixedCollectionStyles(line),
|
|
let .expectedMappingKey(line),
|
|
let .expectedAnchorName(line),
|
|
let .expectedAliasName(line),
|
|
let .incompatibleYAMLDirective(line),
|
|
let .directiveWithoutDocument(line),
|
|
let .unterminatedTag(line),
|
|
let .unterminatedQuotedString(line),
|
|
let .unsupportedDirective(_, line),
|
|
let .unsupportedMultiDocumentStream(line):
|
|
line
|
|
case let .expectedNode(line, _),
|
|
let .expectedScalarKey(line, _),
|
|
let .invalidTaggedScalar(_, _, line, _),
|
|
let .invalidMergeValue(line, _),
|
|
let .undefinedAlias(_, line, _),
|
|
let .unexpectedEvent(_, _, line, _),
|
|
let .unexpectedToken(_, _, line, _),
|
|
let .nestingTooDeep(line, _),
|
|
let .malformed(_, line, _):
|
|
line
|
|
}
|
|
}
|
|
|
|
public var sourceColumn: Int? {
|
|
switch self {
|
|
case .emptyDocument,
|
|
.tabIndentation,
|
|
.unexpectedIndentation,
|
|
.mixedCollectionStyles,
|
|
.expectedMappingKey,
|
|
.expectedAnchorName,
|
|
.expectedAliasName,
|
|
.incompatibleYAMLDirective,
|
|
.directiveWithoutDocument,
|
|
.unterminatedTag,
|
|
.unterminatedQuotedString,
|
|
.unsupportedDirective,
|
|
.unsupportedMultiDocumentStream:
|
|
nil
|
|
case let .expectedNode(_, column),
|
|
let .expectedScalarKey(_, column),
|
|
let .invalidTaggedScalar(_, _, _, column),
|
|
let .invalidMergeValue(_, column),
|
|
let .undefinedAlias(_, _, column),
|
|
let .unexpectedEvent(_, _, _, column),
|
|
let .unexpectedToken(_, _, _, column),
|
|
let .nestingTooDeep(_, column),
|
|
let .malformed(_, _, column):
|
|
column
|
|
}
|
|
}
|
|
}
|
|
}
|