Commit Graph

3 Commits

Author SHA1 Message Date
18fdf9b69a feat(parsing): add a resumable scanner increment and broaden the mutation suite
Add Scanner.scanStep(), the first increment of true chunked input streaming
(#4): Reader gains isFinal/append(_:)/markFinal(), and peek(_:) flags ranDry
instead of asserting end of input when the buffer runs out mid-fetch and more
chunks may still arrive. scanStep() snapshots the scanner before each
fetchNextToken() and restores it whenever a fetch runs dry, so a construct
spanning a chunk boundary is retried after more input lands rather than
misread as an early end of input. Every existing call site keeps the default
isFinal: true, so scanAll() and batch parsing are unchanged; ranDry can never
be set when isFinal is true, by construction. A token already queued is not
always safe to release, since libyaml's simple-key mechanism can still splice
a KEY token in front of it, so scanStep() ports libyaml's
yaml_parser_fetch_more_tokens release condition.

Proof: StreamingScannerDifferentialTests.swift drives scanStep() at several
chunk sizes over representative cases always, and over the entire
yaml-test-suite manifest (402 cases) behind PUREYAML_RUN_YAML_TEST_SUITE=1,
asserting the token sequence matches scanAll() exactly. That proof caught a
real bug: lastTokenForbidsInlineSequence() read indentEngine.tokens.last,
which goes empty once tokens are released incrementally, silently breaking
the key: - a rejection. Fixed by tracking IndentEngine.lastToken explicitly,
kept in sync with tokens.last so batch behavior (which never dequeues) is
unchanged.

Not yet wired into PureYAMLStreaming; scanStep() and its supporting types stay
internal until that integration is designed.

Also broaden the real-seed mutation property suite (#6) with the three
mutation classes it named but didn't yet cover: invalidControlCharacter,
mixedTabSpaceIndentation, and truncatedFlowCollection. The test now asserts
diagnostic quality, not just pass/fail: line must fall within the mutated
document, and column, when present, must be 1-based (some ParseError cases,
like tabIndentation, are line-only by design).
2026-07-09 23:38:39 +02:00
43b20ab7bc feat(parsing): port libyaml token-fetch loop (block + plain core)
Stage 3 of the faithful libyaml scanner port: the token producer. Translates scan_to_next_token, fetch_more_tokens/fetch_next_token dispatch, and the fetchers for stream start/end, document indicators, block entry, key, value (with the simple-key splice and roll-indent), plus scan_plain_scalar with its line-break folding. Reuses the ported indent engine, simple-key mechanism, character classes, and reader. Constructs not yet ported (flow collections, quoted scalars, anchors, tags, directives, block scalars) throw an explicit 'not yet ported' error rather than mis-scan; the port is not yet wired to the public API.

Milestone: the ported scanner tokenizes '- a:' followed by a same-column 'b:' as siblings (one BLOCK-MAPPING-START), matching libyaml, fixing the original block-mapping bug by construction; a more-indented value still nests. Unit-tested for the sibling case, the nested case, a simple pair, and multi-line plain-scalar folding. 305 tests, no regression.
2026-06-24 10:37:35 +02:00
c3033c356d feat(parsing): begin faithful libyaml scanner port (indent engine)
PureYAML's scanner is a hand-rolled approximation of libyaml's algorithm; its indentation and simple-key bugs are the gap between the two. Rather than keep patching the approximation, re-derive the scanner as a faithful, function-by-function Swift port of libyaml's scanner.c (parser.c to follow), so correctness is by construction. The no-C-runtime constraint is preserved: this translates the algorithm into pure Swift, it does not bind to libyaml.

First piece: the indentation engine under PureYAML.Parsing.LibYAML, a line-for-line port of yaml_parser_roll_indent and yaml_parser_unroll_indent. A block collection opens only when content is strictly more indented than the current level, which fixes the '- a:' / same-column 'b:' mis-nesting by construction. Unit-tested against that exact case (sibling vs nested vs flow-inert). Lands as a parallel implementation verified against libyaml built from the CYaml source; swapped in only once it matches the reference with no regression. docs/LIBYAML_PORT.md records the plan. No public behavior changed yet.
2026-06-24 02:46:29 +02:00