fix(parsing): also reject a plain multi-line key in a flow sequence

A flow-sequence single-pair implicit key must be single-line, so its ':'
must sit on the key's line. The quoted form ('[ "key"\n :value ]') was
already rejected via a crossed line break, but a plain key folds its line
break, hiding it. Compare the simple key's mark line with the ':' line
instead, which catches both forms and still exempts flow mappings.

Surpasses libyaml on DK4H (and keeps ZXT5); whole-suite conformance
398/402, canonical events 308/308.
This commit is contained in:
Mihaela Mihaljevic 2026-06-24 21:53:48 +02:00
parent c236945323
commit 24bb2ea4dd
3 changed files with 12 additions and 10 deletions

View File

@ -23,11 +23,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Reject a multi-line implicit key in a flow sequence. A flow-sequence single-pair
implicit key is single-line (`c-s-implicit-json-key`), so its `:` may not cross a
line break: `[ "key"\n :value ]` is malformed. A flow MAPPING adjacent value may
still span lines (`{ "foo"\n :bar }` stays valid), so the rejection is scoped to
flow levels that are sequences, tracked alongside the flow-level stack. Surpasses
libyaml on ZXT5.
implicit key is single-line (`c-s-implicit-json-key`), so its `:` must sit on the
key's line: both `[ "key"\n :value ]` and `[ key\n : value ]` are malformed. A
flow MAPPING adjacent value may still span lines (`{ "foo"\n :bar }` stays
valid), so the rejection is scoped to flow levels that are sequences, tracked
alongside the flow-level stack. The key/`:` line comparison catches the plain-key
form too, which folds its line break. Surpasses libyaml on ZXT5 and DK4H.
- Reject a block sequence that opens on the same line as an earlier node. A `-`
entry mid-line after an inline mapping value (`key: - a`) or a node property
(`&anchor - x`) is invalid, while a `-` after another `-` stays a valid compact

View File

@ -314,8 +314,9 @@ extension PureYAML.Parsing.LibYAML.Scanner {
// (it went stale across the line break), so its value may open a sequence.
lastValueWasInline = simpleKeys[top].possible
// A flow-sequence single-pair implicit key must be single-line, so its `:`
// may not cross a line break; a flow-mapping adjacent value may.
if simpleKeys[top].possible, crossedLineBreak, flowIsSequence.last == true {
// must sit on the key's line (`[ "k"\n :v ]` and `[ k\n : v ]` are both
// invalid); a flow-mapping adjacent value may span lines (`{ "k"\n :v }`).
if simpleKeys[top].possible, flowIsSequence.last == true, simpleKeys[top].mark.line != mark.line {
throw ScannerError(
context: "while scanning a simple key",
problem: "could not find expected ':'",

View File

@ -10,8 +10,8 @@ source:
# oracle: json if in.json present, else none
# status: passing (PureYAML conformant today) | gap (not yet conformant)
total: 402
passing: 397
gap: 5
passing: 398
gap: 4
cases:
- id: "229Q"
name: "Spec Example 2.4. Sequence of Mappings"
@ -1490,7 +1490,7 @@ cases:
localPath: yaml-test-suite/DK4H/in.yaml
expected: reject
oracle: none
status: gap
status: passing
byteCount: 22
lineCount: 3
- id: "DK95/00"