The ported engine wins every conflict: main's post-fork patches to the hand-rolled Scanner and TokenEventParser land on deleted files and are dropped; their behaviors are carried by the port and guarded by the whole-suite conformance gate (402/402 passing). Merge adaptations, all gates green (style, namespacing, forbidden patterns, changelog, roadmap, swiftformat, swiftlint strict, build, full test suite, whole-suite conformance sweep): - PureYAMLJSON representability rules move onto the Check algebra, replacing the retired legacy Rule type. - The permissive tag-handle pre-pass is removed; the port rejects an undefined handle at parse time (suite case QLJ7) and the validation report carries it as a parse diagnostic. - EventStreamComposer's nested types split one-per-file per the namespacing gate. - Tests pinned to old-engine behavior were re-verified against the reference and updated: libyaml rejects an explicit-key continuation ending at a value colon, and suite case QB6E requires rejecting a quoted continuation at column 0. - CHANGELOG unreleased entries from both lines are preserved in two groups with a provenance note. Closes #1, closes #3
90 lines
3.0 KiB
Swift
90 lines
3.0 KiB
Swift
extension PureYAML.Parsing.Parser {
|
|
func composeScalarValue(
|
|
_ value: String,
|
|
tag: String?,
|
|
style: PureYAML.Parsing.ScalarStyle,
|
|
mark: PureYAML.Parsing.Mark,
|
|
) throws -> PureYAML.Model.Value {
|
|
if let tagged = try composeTaggedScalarValue(value, tag: tag, mark: mark) {
|
|
return tagged
|
|
}
|
|
|
|
// An explicit tag that is not a recognized core type, a local tag like `!foo` or the
|
|
// non-specific `!`, still fixes the node as a string: a tagged scalar is not subject to the
|
|
// implicit plain-scalar resolution that would otherwise read `! 12` as the integer 12.
|
|
if normalizedTag(tag) != nil {
|
|
return .string(value)
|
|
}
|
|
|
|
switch style {
|
|
case .folded, .literal:
|
|
return .string(value)
|
|
case .plain:
|
|
return try parseScalar(value, line: mark.line)
|
|
case .doubleQuoted, .singleQuoted:
|
|
return .string(value)
|
|
}
|
|
}
|
|
|
|
func composeTaggedScalarValue(
|
|
_ value: String,
|
|
tag: String?,
|
|
mark: PureYAML.Parsing.Mark,
|
|
) throws -> PureYAML.Model.Value? {
|
|
guard let tag = normalizedTag(tag) else {
|
|
return nil
|
|
}
|
|
switch tag {
|
|
case "!":
|
|
// The non-specific `!` tag resolves a scalar by kind alone: a scalar is
|
|
// a string, with no implicit typing, so `! 12` is "12" not the int 12.
|
|
return .string(value)
|
|
case "tag:yaml.org,2002:str":
|
|
return .string(value)
|
|
case "tag:yaml.org,2002:int":
|
|
guard let int = parseInteger(trim(value)) else {
|
|
throw invalidTaggedScalar(tag: "tag:yaml.org,2002:int", value: value, mark: mark)
|
|
}
|
|
return .int(int)
|
|
case "tag:yaml.org,2002:float":
|
|
guard let double = parseDouble(trim(value)) else {
|
|
throw invalidTaggedScalar(tag: "tag:yaml.org,2002:float", value: value, mark: mark)
|
|
}
|
|
return .double(double)
|
|
case "tag:yaml.org,2002:bool":
|
|
return try composeTaggedBoolValue(value, mark: mark)
|
|
case "tag:yaml.org,2002:null":
|
|
return .null
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func composeTaggedBoolValue(
|
|
_ value: String,
|
|
mark: PureYAML.Parsing.Mark,
|
|
) throws -> PureYAML.Model.Value {
|
|
guard let bool = parseBool(trim(value)) else {
|
|
throw invalidTaggedScalar(tag: "tag:yaml.org,2002:bool", value: value, mark: mark)
|
|
}
|
|
return .bool(bool)
|
|
}
|
|
|
|
func normalizedTag(_ tag: String?) -> String? {
|
|
PureYAML.Parsing.TagNormalizer.normalize(tag)
|
|
}
|
|
|
|
func invalidTaggedScalar(
|
|
tag: String,
|
|
value: String,
|
|
mark: PureYAML.Parsing.Mark,
|
|
) -> PureYAML.Parsing.ParseError {
|
|
PureYAML.Parsing.ParseError.invalidTaggedScalar(
|
|
tag: tag,
|
|
value: value,
|
|
line: mark.line,
|
|
column: mark.column,
|
|
)
|
|
}
|
|
}
|