Commit Graph

44 Commits

Author SHA1 Message Date
16da7248c7 fix(parsing): complete flow-collection key and empty-node handling
Implement libyaml's simple-key mechanism for flow context: the scanner records a potential key position before a plain or quoted scalar, an anchor/tag, or a [/{ opener, and a later ':' splices a mappingKey token retroactively in front of that node. This lets a quoted scalar ("k":v), a nested collection ({k}:v), or a property-carrying node (&c c: d) become a flow mapping key. In flow context ':' is always a value indicator and '?' always an explicit-key indicator regardless of the next character (the block-only following-blank lookahead is disabled), so adjacent forms and trailing '?' parse, and multi-line plain keys fold before the ':' is read. The flow parser is rebuilt around the flow_sequence_entry / flow_mapping_key / flow_mapping_value productions, composing empty scalars for absent keys and values. The streaming token cursor now buffers an open flow collection's tokens until it closes so the retroactive key splice stays valid.

Flips 10 official YAML test suite cases (348/402): 4FJ6, 8KB6, 9BXH, 9MMW, CN3R, DFF7, FRK4, NJ66, UT92, CT4Q. Flow collections used as block mapping keys (LX3P, 6BFJ) need the splice in block context and stay tracked. Updates manifest, fixtures, counts, and roadmap.
2026-06-23 23:18:59 +02:00
1875d66d46 fix(parsing): parse multi-line and block scalars at the document root
Model libyaml's parser->indent (the enclosing block-collection column, -1 at the bare root) separately from per-line indentation, via a blockIndent stack that rolls on block-sequence entries and mapping keys, unrolls at each block-line start, and resets at document boundaries. Plain-scalar continuation folding now compares against blockIndent, so a root scalar folds its column-0 continuations (single break to space, blank line to newline, per-line whitespace stripped) while a scalar inside a collection still ends at a sibling line. The ':' value indicator deliberately does not roll the block indent.

A '---' document-start marker may now be followed by the document's root node on the same line ('--- foo', '--- [1, 2]', '--- |', '--- >'), and a block scalar whose body sits at the document root's column 0 is captured and ends at the next '---'/'...' marker.

Flips 33 official YAML test suite cases (338/402): 18 false-rejects and 12 value mismatches now match, and 3 invalid inputs (9KBC, ZVH3, 9MQT/01) are now correctly rejected. M7A3 and NB6Z now parse but with mismatched values (separate multi-doc and tab-folding gaps) and stay tracked. Adds root multi-line plain scalar regression tests; updates manifest, fixtures, counts, and roadmap.
2026-06-23 22:56:33 +02:00
318913baeb fix(emitting): escape CRLF per unicode scalar in double-quoted output
A CR+LF pair forms a single Swift extended grapheme cluster, so quote()'s Character-level switch matched neither '\\r' nor '\\n' and emitted the line break unescaped. The folding parser then read the dumped value back differently, breaking parse/dump/parse stability for any string containing CRLF (surfaced as a round-trip failure on the Zoom OpenAPI corpus seed under PUREYAML_RUN_FULL_CORPUS). Iterating over unicode scalars escapes CR and LF independently. Adds a dumper regression test.
2026-06-23 22:23:40 +02:00
1de1fcf2a8 fix(parsing): reject invalid input that was wrongly accepted
Tighten error detection per the YAML 1.2 spec across four rules: (1) a tab may never supply block-structure indentation (line-start indentation, block-scalar indentation, and separation before a nested block node are rejected; a tab separating an indicator from a scalar value stays valid); (2) a ---/... document marker inside an open quoted scalar or flow collection is rejected instead of silently ending the document; (3) a %YAML/%TAG line that opens a second explicit document with no intervening ... is rejected; (4) an anchor cannot be attached to an alias node.

This repairs 4 of the 5 error-detection regressions introduced by buckets 3-5 (MUS6/01, N782, SU74, Y79Y/009); 9MQT/01 is deferred (its invalidity is in same-line content after the --- marker, which needs document-content scanning that risks the baseline). Rejects 13 accepted-invalid suite cases and fixes 2 more by value (6BCT, Y79Y/010); 305/402 passing.

BEHAVIOR CHANGE: tab-indented block structure (previously parsed permissively) is now rejected per spec; no real-world corpus seed relied on this. Updates the manifest, fixtures, counts, two affected tests (with spec justification), and the roadmap (bucket 6 marked PARTIAL).
2026-06-23 22:13:35 +02:00
cd05976fac feat(parsing): handle directives and document-end boundaries
Three root causes: (1) a '%' begins a directive only in directive position (before document content, outside flow); everywhere else it is plain content, fixing misfires inside plain scalars, flow mappings, and block scalars. (2) %YAML accepts any 1.x (a higher minor is treated as 1.2 without error), rejects major != 1 and duplicate %YAML, and requires a following '---'; reserved and %TAG directives are accepted and ignored. A directive not followed by a document start is rejected with the new directiveWithoutDocument error. (3) An explicit '...' end marker closes the current document so following content begins a fresh document in parseStream; single-document parse still rejects multi-document input at compose time.

Tests/UnsupportedYAMLGapsFixtures.swift, StreamParsingTests, ScannerTests, and ParsingErrorTests were updated in lockstep to assert the now-correct behavior (percent-after-content is plain text; '...' then content is two documents; %YAML 1.3 is valid while 2.0 and duplicate %YAML are rejected); no test was weakened and multi-document rejection for single-document parse is still covered.

Flips 15 official YAML test suite cases (295/402); SF5V, 9MMA, B63P, H7TQ now correctly rejected. 6LVF and W4TN are reclassified to json-mismatch (blocked by other scalar gaps). Updates the manifest, fixtures, counts, and roadmap.
2026-06-23 21:31:58 +02:00
dfb498a89c fix(parsing): accept anchors, tags, and aliases as mapping keys
A mapping key is a full node: it may carry &anchor and !tag properties and may itself be an *alias. Fixes: (1) anchor/alias name scanning now stops at the first non-name character per yaml_parser_scan_anchor, so *a: reads as alias 'a' plus a mapping indicator instead of name 'a:'; (2) the block-mapping parser enters on a leading node property or alias, attaches same-line key properties to the key node, and emits alias keys directly; (3) an anchor or tag at value position with no same-line node composes an empty (null) value carrying the property, so 'a: &anchor' registers the anchor; (4) the composer registers an anchor's resolved model value (an empty anchored scalar registers null); (5) implicit keys with trailing spaces before the colon are recognized.

Flips 10 official YAML test suite cases to passing (280/402), including G9HC now correctly rejected. 2SXE no longer false-rejects but still value-mismatches on compact-mapping interpretation (a separate gap), so it is reclassified in the manifest rather than removed. Updates the manifest, fixtures, counts, and roadmap.
2026-06-23 21:07:47 +02:00
cdf5f082f8 fix(parsing): support empty (null) nodes in every position
Compose an empty scalar wherever a node is grammatically required but the next token is a structural indicator or line/stream end, mirroring libyaml's process_empty_scalar: after a tag or anchor property with no node, as an absent mapping value (block and flow), as an absent mapping key (both the plain ': v' form and the explicit '?' form), in flow empty key/value forms ({ : }, { , : v }), and for an indented block node following properties. Also fixes a pre-existing block-sequence bug that nested a sibling '-' as a child when only properties remained on the entry line.

Empty scalars resolve through the existing resolver against the empty string, so !!str yields the empty string, bare empty or !!null yields null, and an empty key yields the empty string.

Flips 20 official YAML test suite cases to passing (270/402). CT4Q no longer false-rejects but still value-mismatches on flow plain-scalar folding (a separate gap), so it is reclassified in the manifest rather than removed. Updates the gap manifest, fixtures, counts, and roadmap.
2026-06-23 20:40:40 +02:00
88b67ff0b2 fix(parsing): apply flow folding to quoted scalars
Single (') and double (") quoted multi-line scalars now apply YAML 1.2 flow folding (sections 6.5, 7.3.1, 7.3.2): trailing whitespace before a break is stripped, leading whitespace on continuation lines is stripped, a single break between non-empty lines folds to one space, and N consecutive breaks yield N-1 literal line feeds (first and last lines keep their own leading/trailing spaces as content). A double-quoted backslash at end of line suppresses the break entirely.

Complete the double-quoted escape set: add \xXX and \UXXXXXXXX hex escapes plus the previously missing \0 \a \v \e, literal backslash-space, and named breaks \N \_ \L \P (existing \uXXXX surrogate-pair handling kept). The folding state machine mirrors scanner.c yaml_parser_scan_flow_scalar; implemented in Sources/Parsing/Scalar.swift.

Flips 30 official YAML test suite cases to passing (250/402). Updates the gap manifest, fixtures, count assertions, and roadmap.
2026-06-23 20:17:56 +02:00
3db3e87d39 fix(parsing): correct block scalar folding and chomping
Rewrite literal (|) and folded (>) block scalar content to YAML 1.2 section 8.1: preserve interior blank lines, apply 8.1.3 line folding (a single break between equally indented non-empty lines folds to a space, while blank lines and more-indented lines keep their breaks), preserve tabs in content (only block-indentation columns are stripped), and support the + keep chomping indicator alongside clip and strip.

The block scalar is now scanned as a single unit (header line plus all content lines) with indentation auto-detection in Scanner.BlockScalar.swift, mirroring the reference scanner, instead of being reassembled from a lossy per-line token array.

Flips 24 official YAML test suite cases to passing (220/402). Updates the gap manifest, vendored fixtures, count assertions, and the conformance roadmap.
2026-06-23 20:01:03 +02:00
16a47df118 docs(parsing): document why the nesting bound is necessary and sufficient 2026-06-23 11:08:30 +02:00
64a171bff4 fix(parsing): bound nesting depth so pathological input errors instead of crashing 2026-06-23 09:29:45 +02:00
5d76d184cb fix(parsing): treat leading '#' in block scalars as literal content 2026-06-23 04:00:07 +02:00
208b892019 feat(parser): harden diagnostics and streaming
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.
2026-06-06 07:57:48 +02:00
37239fe613 fix(parser): match block continuation parsing 2026-06-05 22:12:12 +02:00
3a90df095d fix(ci): prepare 0.1.0 release 2026-06-05 21:20:20 +02:00
68883f2104 feat(validation): add diagnostic report errors 2026-06-05 21:06:42 +02:00
13183a4353 Add machine-readable validation reports 2026-06-05 20:39:32 +02:00
0e92e31d89 Add production validation reports 2026-06-05 20:23:20 +02:00
bc54528353 Harden parser against real YAML fixtures 2026-06-05 19:34:30 +02:00
906f0c454d feat(emitting): dump YAML streams 2026-06-05 17:14:41 +02:00
91a2c24901 feat(tagged): add typed constructor policy 2026-06-05 16:24:11 +02:00
697b9cc519 feat(model): support complex mapping keys 2026-06-05 16:08:45 +02:00
9c45419496 feat(tagged): add tag-preserving validation 2026-06-05 15:35:52 +02:00
e1f8acb3a0 feat(parser): expand YAML merge keys 2026-06-05 15:12:55 +02:00
8be6e68a23 feat(parser): add multi-document stream parsing 2026-06-05 14:55:54 +02:00
92b0d7c92d feat(emitting): broaden literal block fixtures 2026-06-05 13:37:33 +02:00
84a2de9ea1 test(compatibility): document unsupported yaml gaps 2026-06-05 13:29:22 +02:00
efdce11a9a Add scalar compatibility corpus 2026-06-05 13:07:04 +02:00
29ecce451a feat(codable): broaden compatibility coverage 2026-06-05 12:49:20 +02:00
5c3de786bf feat(coding): add unkeyed typed conversion 2026-06-05 12:23:52 +02:00
f80d7460ea feat(coding): add keyed typed conversion 2026-06-05 12:11:53 +02:00
8662de5403 feat(coding): add scalar typed conversion 2026-06-05 11:45:00 +02:00
e26c0917d4 critic-fix(validation): make rules immutable 2026-06-05 11:27:06 +02:00
66de760ff2 feat(validation): add predicate-gated rules 2026-06-05 11:21:23 +02:00
d06a00c9a6 test(emitting): add emitter corpus evidence 2026-06-05 11:13:29 +02:00
5fe9c1b8d1 feat(emitting): add flow collection output 2026-06-05 11:09:58 +02:00
6197c23e6f feat(emitting): add literal block scalar output 2026-06-05 11:06:19 +02:00
35fb919b74 feat(emitting): add scalar output options 2026-06-05 10:40:28 +02:00
7a71110bb4 feat(parsing): support directives and scalar tags 2026-06-05 10:16:34 +02:00
bc04c4815e feat(parsing): compose events into values 2026-06-05 10:07:28 +02:00
bee7683ee2 feat(parsing): parse token stream into events 2026-06-05 09:56:18 +02:00
11e7382ab1 feat(parsing): add reader scanner core 2026-06-05 07:40:23 +02:00
3436160306 feat(parsing): add parse event model
Add internal parsing events with marks, scalar styles, collection styles, alias events, and anchor/tag metadata. Add golden parser event tests for current block parser behavior.

Closes #2
2026-06-05 07:16:23 +02:00
9c718e3303 feat(package): bootstrap pure swift yaml package 2026-06-05 06:34:20 +02:00