PureXML/Sources/Parsing/Diagnostic.swift
Mihaela Mihaljevic 4b03c45434 feat(parsing): Namespaces 1.0 constraint enforcement
The namespace layer rejects malformed qualified names, declarations of
the xmlns prefix, misbindings of the xml prefix and either reserved
namespace name (including as the default namespace), and prefix
undeclaration; attributes must be distinct by expanded name; PI targets
and entity/notation names are NCNames; and DTD-typed xmlns values bind
their normalized form. Clears all 18 namespace cases from the eduni
baseline; xmltest valid/sa/012 joins the documented deviations per the
suite's own NAMESPACE='no' flag.

Closes #136
2026-06-10 08:06:45 +02:00

57 lines
2.7 KiB
Swift

public extension PureXML.Parsing {
/// A located problem found while reading a document. Unlike a thrown
/// ``ParseError``, a diagnostic does not abort the read: the recovering reader
/// records it, repairs as best it can, and continues, so an invalid document
/// still yields a best-effort tree alongside the list of what went wrong.
struct Diagnostic: Equatable, Sendable, CustomStringConvertible {
/// A human-readable, already-located description of the problem.
public var message: String
/// The source position, when known.
public var mark: Mark?
public init(message: String, mark: Mark? = nil) {
self.message = message
self.mark = mark
}
public var description: String {
message
}
}
}
extension PureXML.Parsing.Diagnostic {
/// Wraps a thrown ``PureXML/Parsing/ParseError`` as a diagnostic, keeping its
/// located message and structured position.
init(_ error: PureXML.Parsing.ParseError) {
self.init(message: error.description, mark: error.mark)
}
}
public extension PureXML.Parsing.ParseError {
/// The source position the error occurred at, when the case carries one.
var mark: PureXML.Parsing.Mark? {
switch self {
case .emptyDocument, .malformedEncoding, .notImplemented:
nil
case let .unexpectedEndOfInput(mark), let .unterminatedTag(mark), let .unterminatedComment(mark),
let .unterminatedCDATA(mark), let .expectedName(mark), let .expectedEquals(mark),
let .unquotedAttributeValue(mark), let .amplificationLimitExceeded(mark),
let .junkAfterDocumentElement(mark), let .unsupportedDoctype(mark), let .malformedDeclaration(mark),
let .doubleHyphenInComment(mark), let .rawLessThanInAttribute(mark),
let .cdataCloseInContent(mark), let .missingSpaceBeforeAttribute(mark),
let .invalidCharacter(mark), let .reservedProcessingInstructionTarget(mark),
let .invalidEntityDeclaration(mark), let .invalidAttributeListDeclaration(mark),
let .invalidPublicIdentifier(mark):
mark
case let .unexpectedCharacter(_, mark), let .mismatchedEndTag(_, _, mark),
let .namespaceConstraint(_, mark),
let .duplicateAttribute(_, mark), let .invalidReference(_, mark),
let .undefinedEntity(_, mark), let .recursiveEntity(_, mark),
let .unexpectedEndTag(_, mark), let .undefinedNamespacePrefix(_, mark),
let .nestingTooDeep(_, mark), let .nameTooLong(_, mark), let .contentTooLong(_, mark), let .invalidContentModel(_, mark):
mark
}
}
}