A block entry with an inline node recorded only the node's indent (one past
the dash) as a valid implicit level, not the dash's own indent. So a plain
scalar that is an inline sequence item value could not tell a sibling entry
that returns to the sequence indent from its own content, and a compact nested
sequence as an explicit key's value folded into one scalar: `? a` / `: - b` /
` - - c` / ` - d` became `{a: [b - - c - d]}` instead of `{a: [b, [c, d]]}`.
Record the entry's own indent as a sibling level too, so the continuation
stops there. Skip it under a pending explicit key, whose own sequence key
drives the implicit indentation differently (an explicit key whose key is a
sequence, `? - x`, must keep parsing). A block entry more indented than its
container is still plain content, so a wrapped value beginning a line with
`- ` folds in. The block-entry recording moved to a helper to keep the file
within its length limit.
Brings yaml-test-suite value-level conformance to 197/197 (100.0%) with the
parse-level and should-error rejection rates unchanged. 485 tests pass.
A blank line within a block scalar keeps any whitespace past the content
indentation as content, but the leading blank lines, those before the first
content line, were only counted and emitted as empty. So an otherwise-blank
`tab` line under a one-space content indent lost its tab, and a folded scalar
beginning with such a line dropped the leading tab.
Record each leading blank line's whitespace verbatim instead of a count, and
once the content indentation is established emit the surplus past it, the same
way an interior blank line does. A leading blank with no surplus still emits an
empty line, and an empty block scalar (no content indentation) still emits
empty lines for its blanks.
Raises yaml-test-suite value-level conformance to 196/197 (99.5%) with the
parse-level and should-error rejection rates unchanged. 482 tests pass.
A plain scalar continuation stops before a line ending at `:`, since a block
implicit key may not span lines and the next line is a new key. A flow key may
span lines, so the same rule wrongly split `{ multi\n line: v }`: the scalar
returned just `multi` and the parser mis-read `line: v` as a separate entry.
Fold across the `:` in flow as well, leaving the `:` to be scanned as the
value indicator, so the key folds to `multi line`. A block implicit key keeps
the previous behaviour and still stops before the `:`.
Raises yaml-test-suite parse-level conformance to 301/333 (90.4%) and
value-level to 193/195, with the should-error rejection rate unchanged.
476 tests pass.
A flow `?` did not mark an explicit key, so the scalar after it synthesized
its own implicit key: `{? foo : bar}` parsed as `{{foo: bar}: null}` instead of
`{foo: bar}`, and `[? foo : bar]` the same way.
Track the explicit-key state per flow level on the flow context: set it at a
flow `?`, clear it at that level's `:` or a `,`, and discard it with the
context when the collection closes. The key scalar then is not turned into an
implicit key, the pair's `:` is its value indicator, and a nested collection's
`:` does not affect an outer key (`{? {a: b} : c}`). The continuation fold for
a multi-line explicit key now also consults the flow context, restoring
`[? foo\n bar : baz]` to the single key `foo bar`.
The block explicit-key flag is left untouched, since it is not cleared between
valueless `? a` / `? b` entries and folding it into this check regressed
block sets; only the flow path is changed here.
Raises yaml-test-suite value-level conformance to 192/194 (99.0%) with the
parse-level and should-error rejection rates unchanged. 472 tests pass.
A plain scalar continuation that ends at a `:` is normally a new implicit
mapping key, so the scalar stops before it. Under an explicit key (`? foo`
then `bar :`) the `:` is the key's own value indicator instead, so the line is
still key content. The scalar dropped that line and the parser stalled, so
`? foo` then `bar : baz` failed rather than yielding the key `foo bar`.
When the explicit-key marker is pending, fold the continuation line in and
stop, leaving the `:` to be scanned as the value indicator. An implicit key
keeps the previous behaviour, so a continuation ending at `:` still begins a
new key.
The test-suite rates are unchanged, since no comparable case isolates the
block form and the flow form needs separate explicit-key work, but block
explicit keys spanning lines now fold correctly. 466 tests pass.
A comment opens after white space, a tab as well as a space, but the plain
scalar terminator checked only for a space before `#`. So `c: d\t#X` kept the
tab and hash as content, giving the value `d\t#X` rather than `d` with a
trailing comment.
Treat a tab before `#` as a space there, in both the lookahead from a white
space character and the check on the accumulated value's last character. A tab
inside a plain scalar with no `#` after it stays content, and a `#` glued to
content with no white space is still content.
Raises yaml-test-suite value-level conformance to 187/194 (96.4%) with the
parse-level and should-error rejection rates unchanged. 448 tests pass.
Plain scalar line folding strips white space around continuation lines, but
the scanner stripped only spaces, so tabs leaked in. A tab is not indentation,
so the indentation scan left a continuation line's leading tab in place and it
joined the value (`\t3rd` folded as `\t3rd`, not `3rd`), and a line of only
white space holding a tab (` \t`) was treated as a non-blank continuation,
folding to a space rather than the line break an empty line gives.
Skip leading white space, tabs included, before a continuation line's content,
and treat a whitespace-only line that holds a tab as blank when counting the
folded line breaks.
Raises yaml-test-suite value-level conformance to 183/194 (94.3%) with the
parse-level and should-error rejection rates unchanged. 441 tests pass.
A tab is separation white space in YAML, so it follows the `:` mapping-value
indicator exactly as a space does. isMappingValueBoundary (flow) and
isBlockMappingValueBoundary (block) accepted only a space, line break, comma,
or closing bracket, so `foo:\tbar` folded into the plain scalar `foo:\tbar`
instead of the mapping `{foo: bar}`.
Accept a tab in both. A `:` with no following white space (`foo:bar`) is still
plain scalar content, and the symmetric counterpart for a tab after a leading
indicator landed in the previous change.
Raises yaml-test-suite parse-level to 300/333 (90.1%) with the should-error
rejection rate unchanged. 433 tests pass.
A tab is separation white space in YAML, forbidden only for indentation, so it
ends a leading indicator exactly as a space does. isIndicatorBoundary treated
only a space, line break, or end of input as a boundary, so a document marker,
block entry, or explicit key followed by a tab was folded into a plain scalar:
`---\tscalar` parsed to the string `---\tscalar` rather than a document whose
root scalar is `scalar`.
Accept a tab there too. The document-marker and block-entry forms also strip
the tab as separation, so the content is clean; the explicit-key form is now
recognized as well, with post-indicator tab stripping left for a later change.
Raises yaml-test-suite value-level conformance to 175/192 (91.1%) with the
parse-level and should-error rejection rates unchanged. 429 tests pass.
Block style permits only one mapping pair per line, so a scalar followed
by ':' after a block-level value on the same line (a: b: c, a: 'b': c,
x: { y: z }in: valid, or trailing content after a quoted value) is not a
new key but a forbidden inline nested mapping. The scanner synthesized an
implicit key for any scalar followed by ':', regardless of position, so
these parsed as nested mappings instead of failing.
The scanner now records when a line already holds a block-level mapping
pair and suppresses a further implicit key on that line, in plain and
quoted scalars alike. The flag is set only for an implicit-key ':' (one
preceded by its key on the same line): a ':' that opens its line is an
explicit- or null-key value indicator, whose value may be a compact
mapping (? k then : a: 1), so that, flow mappings, next-line nesting, and
colons inside scalars stay valid.
Measured against the official YAML test-suite, parse-level conformance
rises from 256/333 (76.9%) to 260/333 (78.1%) with no regression.
A block scalar terminated by a less-indented comment line failed with a
spurious 'unexpected indentation': once the smaller indentation ended the
scalar, the comment's own column was processed as a dedent, and because no
indentation level held that width the dedent raised an error. A comment's
indentation does not participate in block structure, so a comment that ends
a block scalar is now left for the main loop to scan, with the block
scalar's own first content line (which may itself begin with '#') still
treated as content.
Separately, a whitespace-only line indented past a block scalar's content
level lost its surplus spaces because the width was consumed before the
line was recognized as blank; the surplus is now preserved as the line's
content, so an over-indented blank contributes the correct value.
Measured against the official YAML test-suite, parse-level conformance
rises from 240/333 (72.1%) to 243/333 (73.0%) with matching value-level
gains, and no regression.
A quoted mapping key followed by a space and then ':' ('"key" : value')
failed to parse: the scanner synthesizes the implicit mapping-key token by
checking the character immediately after the key, but a quoted scalar
stops at its closing quote, leaving the separating space, whereas a plain
scalar consumes that space into itself and ends at the colon. The quoted
path now looks past spaces for the colon, which the spec allows between an
implicit key and its value indicator.
Quoted keys with no space, quoted values, and plain keys (which already
worked with a space) are unaffected. Measured against the official YAML
test-suite, parse-level conformance rises from 238/333 (71.5%) to
240/333 (72.1%), with no regression.
A plain scalar at the document root failed to parse when it spanned
multiple lines at column 1 (`a\nb\nc`): the continuation check required a
continuation to be indented more than the scalar, but a root scalar has
nothing enclosing it, so its enclosing-block indent is -1 and a
continuation may start at column 1. The base indentation now returns -1 at
the root, and the continuation stops at a document marker (--- / ...) so a
scalar never folds across a document boundary.
A stream test that asserted two bare plain lines (first / second) were
rejected as extra content was corrected: that input is a valid multi-line
scalar; genuine extra content (a flow node followed by a scalar) is still
rejected, which the test now uses.
Measured against the official YAML test-suite, parse-level conformance
rises from 221/333 (66.4%) to 227/333 (68.2%), with four more documents
also now value-correct and no regression across the existing suite.
A multi-line plain scalar whose value sits one line below its mapping key
stopped after the first line: the continuation check compared the next
line's indent against the value's own indent, which had been pushed onto
the indentation stack, so a continuation at the same indent failed the
strict '>'. It now compares against the parent block's indent (the level
below the value's, when the scalar begins exactly at the indentation top),
matching the spec: a continuation must exceed the mapping's indentation,
not the value's own. Inline values are unaffected, since their top-of-
stack already is the parent block's indent.
Measured against the official YAML test-suite, parse-level conformance
rises from 211/333 (63.4%) to 221/333 (66.4%) with no regression across
the existing 306 tests. The +10 covers the multi-line plain scalar family
the harness flagged, not just the case investigated.
Blank lines between a block scalar header and its first content line come
before the indent token, so the earlier blank-line capture skipped them.
Buffer leading blanks while the block indentation is still pending and
flush them as empty content once the indent is established, in the shared
indentation path used by both scan loops. Also fix folded bodies to emit
a break for a leading blank rather than folding it into a leading space.
This closes the last block-scalar blank-line edge from #57.
The scanner dropped every blank line within and after a block scalar, so
a literal block lost internal blank lines, a folded block turned a blank
line into a space rather than a newline, and the keep indicator could not
preserve trailing blank lines. Capture blank lines as empty content in
both the batch scan loop and the streaming TokenCursor loop, which had
drifted as duplicate copies. Rework blockScalarValue to apply literal
versus folded line semantics and clip/strip/keep chomping over the
captured lines; content without blank lines is unchanged. Re-pin the
multiline-scalar test whose expectation encoded the old dropped-blank
behavior, and add a chomping-and-folding test matrix.
Add structured validation diagnostics, JSON and Yams comparison gates, and lazy token/event parsing so production behavior is measured without retaining full intermediate parser arrays.