diff --git a/.claude/commands/exp b/.claude/commands/exp new file mode 120000 index 0000000..491b78f --- /dev/null +++ b/.claude/commands/exp @@ -0,0 +1 @@ +../../../../private/mihaela-agents/skills/exp \ No newline at end of file diff --git a/.claude/commands/openapi b/.claude/commands/openapi new file mode 120000 index 0000000..773aa45 --- /dev/null +++ b/.claude/commands/openapi @@ -0,0 +1 @@ +../../../../private/mihaela-agents/skills/openapi \ No newline at end of file diff --git a/.claude/commands/swift b/.claude/commands/swift new file mode 120000 index 0000000..a0877ee --- /dev/null +++ b/.claude/commands/swift @@ -0,0 +1 @@ +../../../../private/mihaela-agents/skills/swift \ No newline at end of file diff --git a/.claude/commands/ui b/.claude/commands/ui new file mode 120000 index 0000000..5dafd44 --- /dev/null +++ b/.claude/commands/ui @@ -0,0 +1 @@ +../../../../private/mihaela-agents/skills/ui \ No newline at end of file diff --git a/.githooks/pre-commit b/.githooks/pre-commit index b95a835..1a95981 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -67,6 +67,7 @@ SKIP_PATTERNS=( # Vendored upstream rules canon (mirror of rules-swift). Its enforcement docs # legitimately quote the forbidden phrases. See docs/rules-swift/PROVENANCE.md. '^docs/rules-swift/' + '^Tests/Fixtures/yaml-test-suite/' # Rule files that DEFINE the prohibitions; they MUST be able to cite # the forbidden strings to document them. '/github-discipline\.md$' diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f10b139..059c4db 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,8 @@ blank_issues_enabled: false contact_links: - name: Questions and ideas - url: https://github.com/mihaelamj/PureYAML/discussions + url: https://codeberg.org/Mihaela/PureYAML/discussions about: Ask questions, float ideas, or discuss design in Discussions. - name: Security issue - url: https://github.com/mihaelamj/PureYAML/blob/main/SECURITY.md + url: https://codeberg.org/Mihaela/PureYAML/blob/main/SECURITY.md about: Do not file security issues publicly. Follow the security policy instead. diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index 68dcfa3..d88ec07 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -22,3 +22,14 @@ file is kept to the standard MIT text so it is correctly detected as MIT. The private `PureYAMLResearch` repository contains a full Yams source snapshot for study and compatibility research. That repository is not the implementation source for PureYAML. + +## Vendored test data + +`Tests/Fixtures/yaml-test-suite/` contains input cases vendored from the official +[YAML test suite](https://github.com/yaml/yaml-test-suite) (`data` branch, commit +`6ad3d2c62885d82fc349026c136ef560838fdf3d`), which is distributed under the MIT +license. All 402 cases (numbered sub-cases counted) are vendored, each as its input +(`in.yaml`), expected JSON projection (`in.json`), and/or expected-error marker +(`error`). `Tests/Fixtures/yaml-test-suite-manifest.yaml` records the provenance and +each case's conformance status. These files are test data, not implementation +source. diff --git a/CHANGELOG.md b/CHANGELOG.md index d193238..c58e157 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,453 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Merge the libyaml-port line into main. The ported engine is the sole parser; + the hand-rolled `Scanner`/`TokenEventParser` files and their post-fork + patches are removed. Adaptations made in the merge: the JSON-representability + rules move from the retired legacy `Rule` type onto the Check algebra + (`BuiltinCheck.mappingKeysAreStrings`, `BuiltinCheck.numbersAreFinite` in + `PureYAMLJSON`); the permissive tag-handle pre-pass + (`Scanner.tagHandleIssues`) is removed because the ported engine rejects an + undefined handle at parse time (official suite case QLJ7), so the validation + report carries it as a parse diagnostic; and tests pinned to old-engine + behavior or error text were updated to the reference-verified behavior + (libyaml rejects an explicit-key continuation ending at a value colon, and + suite case QB6E requires rejecting a quoted continuation at column 0). + +The unreleased entries below come from two parallel lines of work, merged +in one step: the libyaml-port line (listed first), whose ported engine is +now the sole parsing engine, and the earlier hand-rolled-engine hardening +line (listed second). Engine-internal file references in the second group +are historical; the behaviors they describe are carried by the port and +guarded by the whole-suite conformance gate. + +### Changed + +- Refresh `docs/YAML_TEST_SUITE_CONFORMANCE.md` to match the manifest: the + headline is 402 passing, 0 gap; the "remaining gaps" narrative is retired; a + closing section records the libyaml-port cutover and the final fix series, + and the manifest is named as the source of truth over the prose. + +### Added + +- The located parse now reports an exact end position for scalars, not just a start: the + scalar event carries the scanner token's end mark, so a `LocatedValue.scalar`'s range covers + the whole token (end exclusive, one past the last character) instead of being start-anchored. + Collections already spanned open to close. The event dump compares value and style, not marks, + so conformance is unaffected; the whole-suite gates stay green. +- Add an opt-in located parse, `PureYAML.parseLocated(_:)` and + `PureYAML.parseStreamLocated(_:)`, returning a `Model.LocatedValue` tree parallel + in shape to `Value` where every node carries its source span (1-based line and + column) and located children. Collections span from their opening to closing + event, scalars carry a start-anchored span, and aliases and merge-inherited pairs + point at their reference site. The plain `Value`, its equality, and the + conformance oracle are untouched: locations are built only when the streaming + composer is asked for them, so the default value path is byte-identical. A + whole-suite test proves the located projection equals a plain parse for every + passing case, including through merge keys and aliases. +- Begin a faithful Swift port of libyaml's scanner under + `PureYAML.Parsing.LibYAML`, to replace the hand-rolled approximation whose + indentation and simple-key bugs the test suite surfaced. The first piece is the + indentation engine, a line-for-line translation 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:` followed + by a same-column `b:` mis-nesting by construction. The port is verified against + libyaml (built from the `CYaml` source) and lands as a parallel implementation, + swapped in only when it matches the reference with no regression. See + `docs/LIBYAML_PORT.md`. No public behavior changed yet. + +### Fixed + +- Reject an under-indented or tab-indented continuation in a multi-line quoted + scalar. A quoted scalar's continuation must be indented past the parent block, so + `"a`\n`b"` (continuation in column 0) and `"bar`\n`\tbaz"` (tab indentation) are + malformed. The error is deferred until the closing quote is found, so an + unterminated quote still reports the missing quote (its root cause) rather than + the indentation symptom. Surpasses libyaml on QB6E and DK95/01, bringing + whole-suite conformance to 402/402. +- Reject a tab used to indent flow-collection content. A tab is never indentation, + so flow content reached through a tab below the continuation indent (`- [`\n + `\tfoo`) is malformed, even though the tab inflates the column. A tab at or past + the indent stays separation, and a tab-only blank line stays blank. Surpasses + libyaml on Y79Y/003. +- Reject a block scalar whose leading empty line is more indented than its first + content line. libyaml auto-detects the deeper indentation and silently drops the + content; the auto-detection now errors when the content line is less indented + than an earlier empty line. Surpasses libyaml on S98Z. +- 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 `:` 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 + sequence (`- - a`) and an explicit key's value on a later line (`? k`\n`: - a`) + stays valid. The inline case is told apart by a pending simple key (an explicit + key's has gone stale across the line break). Surpasses libyaml on 5U3A and SY6V. +- Reject a flow-collection continuation line that is not indented past the parent + block. YAML requires multi-line flow content to be more indented than the + enclosing block context, so `flow: [a,` / `b]` (with `b` in column 0) and the + equivalent multi-line flow mapping are malformed; libyaml does not enforce it. A + closing `]`/`}` or a leading `,` may still sit at any indentation. Surpasses + libyaml on 9C9N and VJP3/00. +- Reject content after a `...` document-end marker on the same line. Only + whitespace and a comment may follow `...`; unlike `--- x`, a `... x` cannot + carry inline content. Surpasses libyaml on 3HFZ. +- Resolve a scalar with the non-specific `!` tag as a string. The `!` tag forces + resolution by kind alone, with no implicit typing, so `! 12` is the string "12" + rather than the integer 12. The typed value now honours it (the event stream + already did). Surpasses libyaml on S4JQ. +- Reject a bare `-` before a flow indicator inside a flow collection. Per + `ns-plain-first` a `-` begins a plain scalar in flow only when a flow-safe + character follows; `[-]` and `[-, -]` are malformed, not a sequence of `-` + scalars. libyaml reads the `-` as a scalar. Surpasses libyaml on G5U8 and YJV2. +- Reject a comment that is not preceded by whitespace. A `#` only begins a comment + after a space, a tab, or at the start of a line; a `#` adjacent to the previous + token (`key: "value"# c`, `[ a ]#c`, `[ a,#c`, a `>#c` block scalar header) is + malformed. The check uses the character immediately before the `#`, since a plain + scalar consumes its own trailing blanks. libyaml accepts the adjacent form. + Surpasses libyaml on 9JBA, CVW2, SU5Z, and X4QW. Whole-suite conformance is now + 388/402. +- Reject a directive that follows a document without an explicit `...` end marker. + Directives apply to the document that follows, so the previous document must be + closed with `...` before them; after an implicit end a `%YAML`/`%TAG`/reserved + directive is now an error. Also reject a `%YAML` version followed immediately by + `#` with no separating space (`%YAML 1.1#...`), since a comment requires leading + separation. Restores reject-side conformance lost when the libyaml port became + the sole engine (9HCY, EB22, MUS6/00, MUS6/01, RHX7). +- Refresh `yaml-test-suite-manifest.yaml` (now version 3): the ported engine's + whole-suite conformance is 384/402, up from the recorded 331, after the + canonical-event and reject-side work. 53 cases the manifest still marked as gaps + now pass. +- Keep the final line break of a block scalar that ends at end of input without a + trailing newline. A whitespace-only last line still counts as one line break + under keep (`+`) chomping, so `- |+` followed by a spaces-only unterminated line + yields `"\n"` rather than `""`. With this the ported engine emits the exact + canonical event stream for every valid case in the vendored YAML test suite + (308/308), surpassing libyaml (252) and the previous hand-rolled parser (267). + Surpasses libyaml on JEF9/02. +- End a root-level block scalar at a `---` or `...` document marker in column 0. + Now that a root block scalar can take indentation 0, its content loop reaches + column-0 lines, so a marker line must end the scalar instead of being folded + into it. Without this a `--- |` literal swallowed the following `...`, the next + directives, and later documents. Surpasses libyaml on W4TN. +- Fold over a tab-only blank line inside a multi-line plain scalar. A plain + scalar may span blank lines, and a blank line that contains a tab is still + blank, so the tab is not indentation. libyaml rejects any tab below the scalar + indentation; the scanner now rejects it only when it indents real content, not + when the rest of the line is blank. Surpasses libyaml on DK95/04. +- Accept a tab as in-line separation while still rejecting it as indentation. A + tab after a `-`, `?`, or `:` indicator, or before a flow collection, is valid + separation, but libyaml refuses to skip it whenever a simple key is allowed and + reports "found character that cannot start any token". The scanner now skips + tabs in the inter-token whitespace and records whether one preceded the token; + a block indicator or an implicit mapping key reached through a tab is rejected + (the tab would be indentation), while a scalar value or flow collection is + accepted. So `- foo:\tbar`, `-\t-1`, `: -\tb`, `\t[ ]`, `\t{}`, and a + space-then-tab continuation parse, while tab-indented keys and `-\t-` style + nested entries are still rejected. Surpasses libyaml on 6BCT, 6CA3, A2M4, + DK95/00, Q5MG, and Y79Y/010. +- Parse a flow sequence entry that begins with `:` as a single-pair mapping with + an empty key (`[ : v ]`). libyaml hands the leading VALUE token to its node + parser and fails. The flow-sequence-entry parser now opens the implicit mapping + on a leading `:` and leaves the indicator for the value state, so the value is + parsed rather than dropped. Surpasses libyaml on CFD4. +- Apply the YAML 1.2 flow `:` rule instead of libyaml's "always a value + indicator in flow". In a flow collection a `:` only ends a node when it is + followed by whitespace, the end of input, or a flow indicator, or when it is + adjacent to a JSON key (a quoted scalar or a flow collection used as the key). + Otherwise the `:` is plain-scalar content. So `[:x]` and `{x: :x}` keep the + scalar `:x`, `http://foo.com` and `::vector` stay single scalars, `"key":value` + and `{JSON: like}:adjacent` bind the value across the adjacent `:`, and + `omitted value:,` is a key with an empty value rather than a scan error. The + pending simple key now records whether it is a JSON node, and the plain scalar + scanner ends (rather than rejecting) at a `:` before a flow indicator. Surpasses + libyaml on 4ABK, 58MP, 5T43, DBG4, FRK4, and HM87/00, with 9MMW (mixed + adjacent/separate keys) still correct. +- Treat `?` in a flow collection as plain-scalar content unless it is followed by + whitespace, the end of input, or a flow indicator. libyaml makes every `?` in + flow context a mapping-key indicator, dropping the `?` from `?foo`, but + `ns-plain-first` lets a `?` followed by a flow-safe character begin a plain + scalar. So `{ ?foo: bar }` keys on `?foo` and `[?x]` is the scalar `?x` rather + than an empty single-pair mapping. Surpasses libyaml on 652Z and HM87/01. +- Accept a tab as block-scalar content once the indentation is satisfied. The + block-scalar break scanner rejected any tab seen while auto-detecting the + content indentation, but a tab at or beyond the content column is content, not + indentation. The tab is now an error only below the content column (the parent + indent + 1 floor while auto-detecting), so `foo: |-` / `bar` lines whose + content begins with a tab parse, while a tab used as indentation (a tab-only + line shallower than the content) is still rejected. Surpasses libyaml on + 96NN/00, 96NN/01, R4YG, and Y79Y/001. +- Auto-detect indentation 0 for a root-level block scalar. The block-scalar + scanner used 0 as the "indentation not yet detected" sentinel and floored the + detected indent at 1 (as libyaml does in `scan_block_scalar_breaks`), so a + `--- >` or `--- |` whose content begins in column 0 detected no content and the + following line was misread as a new document ("did not find expected document + start"). The sentinel is now -1, leaving 0 a representable detected indent, and + the floor is the parent indent + 1 (0 at the document root). Surpasses libyaml + on DK3J, FP8R, and M7A3. +- Parse block mappings with empty (null) keys. A `:` value indicator with no + preceding key on its line denotes a mapping entry whose key is empty, which + YAML 1.2 permits but libyaml rejects with "did not find expected key". The + block-mapping-key parser now emits the empty scalar key and lets the value + state consume the indicator, fixing the canonical event streams for `: a` + style mappings, explicit empty keys (`? &a a` / `: *a`), empty keys nested in + sequences (`- :`, `- ? : x`), and mixed empty-key/value entries. Surpasses + libyaml on these seven test-suite cases (2JQS, 6M2F, M2N8/00, NHX8, S3PD, + SM9W/01, UKK6/00). +- Parse flow mappings with empty (null) keys. The same `:`-without-a-key entry + is valid inside `{ ... }`, where libyaml hands the bare VALUE token to its node + parser and fails with "did not find expected node content". The flow-mapping-key + parser now emits the empty scalar key for a leading `:`, so `{ : }` and + `{ key: value, : empty key }` parse, completing the multi-document NKF9 case. +- Emit no document for a stream whose only content is comments or whitespace. A + comment-only or empty stream has zero documents in YAML 1.2 (matching libyaml + and the test suite), but the event stream was emitting a spurious empty null + document. Found by differential testing against libyaml over real-world YAML + (a comment-only `values.yaml`) in addition to the canonical event gate. The + single-document value API still maps an empty stream to `null`, so + `PureYAML.parse("")` is unchanged. Fixes 8G76, 98YD, and AVM7, raising exact + canonical-event conformance to 267 of 308. + +- Strip the trailing folded line break from a flow-context plain scalar. A plain + scalar inside `[...]`/`{...}` whose next line begins with a flow indicator + (`,` `]` `}`) or the `:` value indicator was retaining the line break folded to + a trailing space (for example `[\nfoo: bar\n]` produced the value `"bar "`), + which YAML 1.2 section 7.3.3 forbids. Derived from the plain-scalar production + and verified against the canonical event gate: fixes 10 official YAML test suite + cases (4FJ6, 4MUZ/02, CT4Q, LP6E, NKF9, QF4Y, VJP3/01, Y79Y/002, ZF4X, ZK9H) + with no regression, raising exact canonical-event conformance to 264 of 308. + +### Added + +- Add an authoritative canonical-event conformance gate. The parser's event + stream is serialized into the official YAML test suite event (yeast) format and + compared exactly to each case's vendored `test.event`, which checks anchors, + tags, scalar styles, flow vs block, and explicit document markers for every + valid case (including the roughly half with no `in.json` projection). This + replaces the JSON-projection oracle, which was lossy: measured against ground + truth, 254 of 308 valid suite cases emit exactly correct events (40 emit a + wrong event stream, 14 false-reject), where the JSON proxy had reported a higher + figure. The gate records the gap set and fails on any regression or unrecorded + fix. All 402 cases' `test.event` files are vendored alongside their inputs. + +### Changed + +- Record whether a document boundary was explicit in the parser `Event` model + (`documentStart`/`documentEnd` now carry an `explicit` flag), so a `---`/`...` + marker is distinguished from an implicit boundary. This is required for exact + canonical-event comparison and resolves 89 cases that were previously correct + but unverifiable. + +### Fixed + +- Make the YAML test suite conformance gate comprehensive and repair the + regressions it revealed. The gap-only manifest (which deleted a case once fixed, + so nothing guarded it afterward and later work could silently regress it) is + replaced by a full manifest of all 402 official cases + (`Tests/Fixtures/yaml-test-suite-manifest.yaml`), each with its `id`, `name`, + `localPath`, conformant `expected` behavior, `oracle`, `byteCount`, `lineCount`, + and a `status` (`passing` | `gap`). Every case's files are vendored under + `Tests/Fixtures/yaml-test-suite/`. The gated sweep + (`PUREYAML_RUN_YAML_TEST_SUITE=1`) now asserts every `passing` case still passes + and every `gap` still reproduces, so a regression in any passing case fails the + sweep. Result at the pinned commit: **329 of 402 passing, 73 gap.** +- Stop over-rejecting tabs. A tab is invalid only as block-structure indentation + (`scanner.c` `scan_to_next_token` / `scan_block_scalar_breaks` / + `scan_plain_scalar`). Block indentation is now measured in spaces only; a tab is + left for the token scanner, which allows it inside block-scalar content once a + leading space fixes the content column (96NN/00, 96NN/01, R4YG, Y79Y/001), as + separation before a scalar value (DK95/00) or a flow node (6CA3, Q5MG, J3BT), and + on a whitespace-only blank line (DK95/03, DK95/07), while still rejecting genuine + tab indentation (4EJS, Y79Y/000, Y79Y/004-008, DK95/06). The batch scanner and the + incremental token cursor were unified onto a single `scanStep`, since their + divergence previously let the streaming parser miss a tab error the batch scanner + caught. +- Restore anchors/aliases as mapping keys for `26DV`: an anchor on a `key:` value + line followed by an indented `*alias :` key now anchors the nested mapping rather + than the alias key (which cannot carry properties); `&b *alias` on one line is + still rejected (SU74). +- Restore flow bare-tag/anchor keys for `WZ62` (`{ foo : !!str, !!str : bar, }` to + `{"foo":"", "":"bar"}`): a flow key introduced by a spliced `mappingKey` uses the + same key parser as the implicit form, so a bare tag before the `:` composes an + empty tagged scalar key instead of a mapping-as-key. +- Complete flow-collection (`[...]`, `{...}`) parsing for keys, empty nodes, and + multi-line scalars, fixing 10 official YAML test suite cases and removing them + from the conformance gap manifest. The scanner now implements libyaml's + simple-key mechanism inside flow context: a potential key position is recorded + before a plain or quoted scalar, an anchor or tag, or a nested `[`/`{` opener, + and a later `:` value indicator splices a `mappingKey` token in front of that + node so a collection or property-carrying node can be a flow-mapping key. In + flow context a `:` is now always a value indicator and a `?` always an explicit + key indicator regardless of the following character (matching libyaml's + `flow_level || IS_BLANKZ_AT` checks), so `"k":v`, `{k}:v`, and a trailing `?` + parse correctly; the implicit-key forward lookahead is restricted to block + context. A multi-line plain key folds in full before its `:` is read. The flow + parser was rebuilt around libyaml's flow productions (`flow_sequence_entry`, + `flow_mapping_key`/`value`), composing empty scalar keys and values where + absent. The streaming token cursor holds an open flow collection's tokens until + it closes so the retroactive key splice stays valid. Fixed false-rejects 4FJ6, + 8KB6, 9BXH, 9MMW, CN3R, DFF7, FRK4, NJ66, UT92 and corrected values for CT4Q. + The flow-node-as-block-mapping-key cases LX3P and 6BFJ remain tracked (they need + the block-context simple-key splice, a separate change). + +- Parse multi-line plain scalars and block scalars at the document root, fixing 35 + official YAML test suite cases and removing them from the conformance gap + manifest. The scanner now tracks the enclosing block-collection indent + (libyaml's `parser->indent`) separately from per-line indentation, defaulting to + -1 at the bare document root, so a plain scalar's continuation lines fold using + the spec rule "more indented than the enclosing block": 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. 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 captures that body and + ends at the next `---`/`...` marker. Fixed false-rejects 35KP, 4CQQ, 4Q9F, 6JQW, + 82AN, 93WF, 96L6, 9MQT/00, 9YRD, B3HG, DK3J, EX5H, EXG3, FP8R, RZT7, T26H, UGM3, + XLQ9; corrected values for 27NA, 2G84/02, 2G84/03, 4WA9, 6FWR, 6LVF, A2M4, K54U, + KSS4, L383, T5N4, W4TN; and started correctly rejecting the invalid 9KBC, ZVH3, + 9MQT/01. The still-imperfect M7A3 (multi-document `...` splitting) and NB6Z (tabs + on empty plain-scalar lines) now parse but with mismatched values and stay + tracked. Added root multi-line plain scalar regression tests. + +- Escape carriage returns and line feeds in double-quoted output per unicode + scalar rather than per Character. A CR+LF pair forms a single Swift extended + grapheme cluster, so the previous Character-level escape switch matched neither + `\r` nor `\n` and emitted the pair unescaped; the folding parser then read it + back differently, breaking parse/dump/parse stability for values containing + CRLF (observed on the Zoom OpenAPI corpus seed). Added a dumper regression test. + +- Tightened error detection so 15 more official YAML test suite cases are handled + correctly, repairing four error-detection regressions and removing them from the + conformance gap manifest. Tabs are now rejected when they would supply + block-structure indentation: a tab at the start of a block line, a tab in a + block scalar's indentation, and a tab in separation position that precedes a + nested block node (a `-` entry, a `?` key, or a compact mapping key) all fail, + while a tab used purely as in-line separation before a scalar value stays valid + (4EJS, Y79Y/000, Y79Y/004, Y79Y/005, Y79Y/006, Y79Y/008, Y79Y/009 now reject; + 6BCT and Y79Y/010 now parse with matching values; DC7X and J3BT no longer + falsely reject). A `---`/`...` document marker at column 0 is now rejected when + it appears inside an open flow collection (N782) or inside an open quoted scalar + (RXY3, 5TRB) rather than silently ending the document. A second `%YAML`/`%TAG` + directive section that opens a new document without an intervening `...` suffix + is rejected (MUS6/01). An anchor or tag attached to an alias node, and an + anchor-plus-alias on one node, are rejected (SU74, SR86). Remaining + accepted-invalid cases that need `---`-line content scanning or full simple-key + tracking (for example 2G84/00, 2G84/01, 9MQT/01, ZCZ6) are left tracked in the + gap manifest. +- Added YAML directive handling and completed document-boundary support, fixing + three root causes. First, a `%` now begins a directive only in directive + position (before any document content and before the `---` that starts a + document, including immediately after a `...` end marker); everywhere else, and + in any flow context, `%` is ordinary plain text rather than a misfiring + directive. Second, `%YAML` is parsed leniently per the spec: a `1.x` version is + accepted (a higher minor is treated as 1.2 with a warning rather than an + error), while an unsupported major version, a duplicate `%YAML` in one + document, or extra non-comment fields are rejected; reserved and unknown + directives (and `%TAG` handle definitions) are accepted and ignored, and a + directive must be followed by a `---` document start. Third, a `...` end marker + now closes the current document so that following content begins a fresh + document in the multi-document stream parser (`parseStream`), while the + single-document `parse` still rejects multi-document input. This makes 11 + official YAML test suite cases parse with matching values (2LFX, 5TYM, 6WLZ, + 6ZKB, 7Z25, 9DXL, 9WXW, BEC7, MUS6/03, MUS6/05, MUS6/06), correctly rejects + four previously accepted-invalid cases (9MMA, B63P, H7TQ, SF5V), and unblocks + 6LVF and W4TN from parse errors to value comparisons that now depend on + separate scalar gaps (`---`-line content and literal block chomping). +- Rewrote literal (`|`) and folded (`>`) block scalar content handling to follow + YAML 1.2 §8.1 semantics, fixing four root causes: interior blank lines are no + longer dropped from literal scalars; folded scalars now apply true §8.1.3 line + folding (a single break between equally indented non-empty lines folds to a + space, blank lines stay literal newlines, and more-indented lines keep both + their leading whitespace and their surrounding breaks unfolded); tabs inside + block scalar content are preserved instead of being rewritten as spaces (only + the block indentation columns are stripped); and the `+` keep chomping + indicator is now supported alongside clip and strip. The block scalar is now + scanned as a single unit (header line plus all content lines) with indentation + auto-detection, mirroring the reference scanner, rather than reassembled from a + lossy per-line token array. This makes 24 additional official YAML test suite + cases pass: 4QFQ, 5LLU, 6VJK, 7T8X, 96NN/00, 96NN/01, DWX9, F6MC, F8F9, H2RW, + JEF9/00, JEF9/01, K527, K858, L24T/00, L24T/01, M29M, M9B4, MJS9, P2AD, R4YG, + TS54, W9L4, and Y79Y/001. +- Implemented YAML 1.2 flow (quoted) scalar line folding for both single (`'`) + and double (`"`) quoted scalars, mirroring the reference scanner's + `yaml_parser_scan_flow_scalar`. Multi-line quoted scalars now fold correctly: + trailing whitespace before a break is stripped, leading whitespace on a + continuation line is stripped, a single break between non-empty lines folds to + one space, and N consecutive breaks yield N-1 literal line feeds (the first and + last lines keep their own leading and trailing spaces as content). A double + quoted backslash at end of line now suppresses the break entirely (no space, no + newline). Completed the double quoted escape set with `\xXX` (2 hex digits) and + `\UXXXXXXXX` (8 hex digits), and added the previously missing `\0 \a \v \e`, + literal `\`, and the named breaks `\N \_ \L \P`, alongside the existing + `\uXXXX` (including surrogate pairs). This makes 30 additional official YAML + test suite cases pass: 3RLN/00, 3RLN/01, 3RLN/02, 3RLN/03, 3RLN/04, 3RLN/05, + 4ZYM, 565N, 5GBF, 6WPF, 7A4E, 8UDB, 9SA2, 9TFX, DE56/00, DE56/01, DE56/02, + DE56/03, DE56/04, DE56/05, DK95/02, DK95/08, G4RS, NAT4, NP9H, PRH3, Q8AD, + T4YY, TL85, and XV9V. +- Composed an empty (null) plain scalar wherever a node is grammatically required + but absent, instead of raising "expected a YAML node". This single production + mirrors `parser.c`'s empty-scalar fallback and covers every position a node can + go missing: after a tag or anchor property with no following node, an absent + mapping value, an absent mapping key (both the plain `: value` form and the + explicit `?` form), and the empty key and value forms inside flow collections. + An empty node carrying an anchor or tag is explicit; a bare absent node with no + property in a grammatically-required position is still a parse error, matching + the reference parser. The empty scalar resolves through the normal scalar + resolver against an empty value, so `!!str` yields `""`, `!!null` and a bare + empty yield null, and an empty key resolves like any other empty scalar. + Implemented in `Sources/Parsing/TokenEventParser.EmptyNode.swift` with the + flow and block call sites in the sibling `TokenEventParser.*` files. This makes + 20 additional official YAML test suite cases pass: 2JQS, 2XXW, 5WE3, 6M2F, + 7W2P, BU8L, CFD4, JTV5, KK5P, LE5A, M2N8/00, NHX8, NKF9, PW8X, RZP5, S3PD, + SM9W/01, UKK6/02, WZ62, and XW4D. CT4Q now parses but still mismatches its + expected JSON (a separate flow multi-line plain-scalar folding gap) and is + re-recorded as `json-mismatch`. +- Accepted node properties (anchor, tag) and aliases in mapping-key position, so + a mapping key is parsed as the full node it is: it may carry `&anchor` and/or + `!tag` properties, and it may itself be an `*alias`. Fixed four root causes. + (1) The scanner now terminates an anchor or alias name at the first character + outside libyaml's `IS_ALPHA` set (ASCII letters, digits, `-`, `_`), mirroring + `yaml_parser_scan_anchor`, so `*alias:` reads the alias `alias` followed by a + `:` mapping indicator instead of swallowing the colon into the name. (2) The + block-mapping parser now begins a pair at leading properties or an alias, not + only at the key indicator the scanner emits after them, and properties on the + same line as the first key attach to that key node rather than to the mapping + (`&a a: b` anchors the key `a`, while `&a` alone on its own line anchors the + map). (3) An anchor or tag at value position with no node following on the same + line now composes an empty (null) value that still carries the property, so + `a: &anchor` registers `anchor` as null and a later `*anchor` resolves. (4) An + anchored scalar now registers its resolved value (so an empty anchored scalar + registers null, not `""`). The implicit-key scanner also now recognizes a key + with trailing spaces before its `:` (`"top1" :`). Implemented in + `Sources/Parsing/Scanner.swift`, `Scanner.Helpers.swift`, + `TokenEventParser.swift`, `TokenEventParser.EmptyNode.swift`, + `TokenEventParser.Helpers.swift`, `TokenEventParser.Block.swift`, + `TokenEventParser.Flow.swift`, `TokenCursor.swift`, and the anchor registration + in `EventStreamComposer.swift` and `EventComposer.swift`. This makes 10 + additional official YAML test suite cases pass: 26DV, 6KGN, 74H7, 87E4, 9KAX, + E76Z, G9HC, HMQ5, LQZ7, and ZWK4 (G9HC is an invalid-anchor case that is now + correctly rejected). 2SXE now parses but still mismatches its expected JSON (a + separate compact block-mapping structural gap) and is re-recorded as + `json-mismatch`. + +### Added + +- Track conformance against the official YAML test suite + (github.com/yaml/yaml-test-suite, `data` branch). The 182 cases PureYAML does + not yet handle correctly are vendored under `Tests/Fixtures/yaml-test-suite/` + with a machine-readable manifest (`Tests/Fixtures/yaml-test-suite-gaps.yaml`) + recording each gap's category and current behavior. A new opt-in sweep + (`bash scripts/check-yaml-test-suite.sh`, gated behind + `PUREYAML_RUN_YAML_TEST_SUITE=1`) reproduces every recorded gap so future fixes + must update the manifest. `docs/YAML_TEST_SUITE_CONFORMANCE.md` documents the + measured result (220/402 passing) and the ordered plan for closing the gaps. + ### Added - Opt-in located parse: `parseStreamLocated` returns a source-span projection of every document, diff --git a/Package.swift b/Package.swift index 0e9c8ff..f7f04a1 100644 --- a/Package.swift +++ b/Package.swift @@ -9,20 +9,36 @@ let package = Package( name: "PureYAML", targets: ["PureYAML"], ), + .library( + name: "PureYAMLJSON", + targets: ["PureYAMLJSON"], + ), ], dependencies: [], targets: [ .target( name: "PureYAML", path: "Sources", + exclude: ["PureYAMLJSON"], + ), + .target( + name: "PureYAMLJSON", + dependencies: ["PureYAML"], + path: "Sources/PureYAMLJSON", ), .testTarget( name: "PureYAMLTests", dependencies: ["PureYAML"], path: "Tests", + exclude: ["PureYAMLJSONTests"], resources: [ .copy("Fixtures"), ], ), + .testTarget( + name: "PureYAMLJSONTests", + dependencies: ["PureYAMLJSON"], + path: "Tests/PureYAMLJSONTests", + ), ], ) diff --git a/README.md b/README.md index c373a6c..bcfc392 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # PureYAML -[![Gates](https://github.com/mihaelamj/PureYAML/actions/workflows/gates.yml/badge.svg?branch=main)](https://github.com/mihaelamj/PureYAML/actions/workflows/gates.yml) -[![macOS](https://github.com/mihaelamj/PureYAML/actions/workflows/macos.yml/badge.svg?branch=main)](https://github.com/mihaelamj/PureYAML/actions/workflows/macos.yml) -[![Linux](https://github.com/mihaelamj/PureYAML/actions/workflows/linux.yml/badge.svg?branch=main)](https://github.com/mihaelamj/PureYAML/actions/workflows/linux.yml) -[![Windows](https://github.com/mihaelamj/PureYAML/actions/workflows/windows.yml/badge.svg?branch=main)](https://github.com/mihaelamj/PureYAML/actions/workflows/windows.yml) -[![WASM](https://github.com/mihaelamj/PureYAML/actions/workflows/wasm.yml/badge.svg?branch=main)](https://github.com/mihaelamj/PureYAML/actions/workflows/wasm.yml) -[![Conformance](https://github.com/mihaelamj/PureYAML/actions/workflows/conformance.yml/badge.svg?branch=main)](https://github.com/mihaelamj/PureYAML/actions/workflows/conformance.yml) +[![Gates](https://codeberg.org/Mihaela/PureYAML/actions/workflows/gates.yml/badge.svg?branch=main)](https://codeberg.org/Mihaela/PureYAML/actions?workflow=gates.yml) +[![macOS](https://codeberg.org/Mihaela/PureYAML/actions/workflows/macos.yml/badge.svg?branch=main)](https://codeberg.org/Mihaela/PureYAML/actions?workflow=macos.yml) +[![Linux](https://codeberg.org/Mihaela/PureYAML/actions/workflows/linux.yml/badge.svg?branch=main)](https://codeberg.org/Mihaela/PureYAML/actions?workflow=linux.yml) +[![Windows](https://codeberg.org/Mihaela/PureYAML/actions/workflows/windows.yml/badge.svg?branch=main)](https://codeberg.org/Mihaela/PureYAML/actions?workflow=windows.yml) +[![WASM](https://codeberg.org/Mihaela/PureYAML/actions/workflows/wasm.yml/badge.svg?branch=main)](https://codeberg.org/Mihaela/PureYAML/actions?workflow=wasm.yml) +[![Conformance](https://codeberg.org/Mihaela/PureYAML/actions/workflows/conformance.yml/badge.svg?branch=main)](https://codeberg.org/Mihaela/PureYAML/actions?workflow=conformance.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) PureYAML is a dependency-free YAML package written entirely in Swift. diff --git a/Sources/Emitting/Dumper.swift b/Sources/Emitting/Dumper.swift index c2fea45..e285c81 100644 --- a/Sources/Emitting/Dumper.swift +++ b/Sources/Emitting/Dumper.swift @@ -356,9 +356,13 @@ extension PureYAML.Emitting.Dumper { } func quote(_ value: String) -> String { + // Iterate over unicode scalars, not Characters: a CR+LF pair forms a + // single extended grapheme cluster in Swift, so a Character-level switch + // would match neither "\r" nor "\n" and emit the line break unescaped, + // which does not round-trip through the folding parser. var output = "\"" - for character in value { - switch character { + for scalar in value.unicodeScalars { + switch scalar { case "\"": output += "\\\"" case "\\": @@ -370,7 +374,7 @@ extension PureYAML.Emitting.Dumper { case "\t": output += "\\t" default: - output.append(character) + output.unicodeScalars.append(scalar) } } output += "\"" diff --git a/Sources/Parsing/Event.swift b/Sources/Parsing/Event.swift index 891a27c..1d7d005 100644 --- a/Sources/Parsing/Event.swift +++ b/Sources/Parsing/Event.swift @@ -2,8 +2,8 @@ extension PureYAML.Parsing { enum Event: Equatable, CustomStringConvertible { case streamStart(mark: Mark) case streamEnd(mark: Mark) - case documentStart(mark: Mark) - case documentEnd(mark: Mark) + case documentStart(explicit: Bool, mark: Mark) + case documentEnd(explicit: Bool, mark: Mark) case sequenceStart(anchor: String?, tag: String?, style: CollectionStyle, mark: Mark) case sequenceEnd(mark: Mark) case mappingStart(anchor: String?, tag: String?, style: CollectionStyle, mark: Mark) @@ -17,10 +17,10 @@ extension PureYAML.Parsing { "streamStart @\(mark)" case let .streamEnd(mark): "streamEnd @\(mark)" - case let .documentStart(mark): - "documentStart @\(mark)" - case let .documentEnd(mark): - "documentEnd @\(mark)" + case let .documentStart(explicit, mark): + "documentStart explicit=\(explicit) @\(mark)" + case let .documentEnd(explicit, mark): + "documentEnd explicit=\(explicit) @\(mark)" case let .sequenceStart(anchor, tag, style, mark): "sequenceStart anchor=\(describe(anchor)) tag=\(describe(tag)) style=\(style) @\(mark)" case let .sequenceEnd(mark): @@ -39,6 +39,36 @@ extension PureYAML.Parsing { } extension PureYAML.Parsing.Event { + /// Re-emit the event with libyaml's 0-based line/column mark converted to the + /// package's 1-based convention (the byte index is already 0-based in both). + func bumpingMark() -> Self { + let source = mark + let bumped = PureYAML.Parsing.Mark(line: source.line + 1, column: source.column + 1, index: source.index) + switch self { + case .streamStart: + return .streamStart(mark: bumped) + case .streamEnd: + return .streamEnd(mark: bumped) + case let .documentStart(explicit, _): + return .documentStart(explicit: explicit, mark: bumped) + case let .documentEnd(explicit, _): + return .documentEnd(explicit: explicit, mark: bumped) + case let .sequenceStart(anchor, tag, style, _): + return .sequenceStart(anchor: anchor, tag: tag, style: style, mark: bumped) + case .sequenceEnd: + return .sequenceEnd(mark: bumped) + case let .mappingStart(anchor, tag, style, _): + return .mappingStart(anchor: anchor, tag: tag, style: style, mark: bumped) + case .mappingEnd: + return .mappingEnd(mark: bumped) + case let .scalar(value, anchor, tag, style, _, endMark): + let bumpedEnd = PureYAML.Parsing.Mark(line: endMark.line + 1, column: endMark.column + 1, index: endMark.index) + return .scalar(value: value, anchor: anchor, tag: tag, style: style, mark: bumped, endMark: bumpedEnd) + case let .alias(anchor, _): + return .alias(anchor: anchor, mark: bumped) + } + } + var isMappingEnd: Bool { if case .mappingEnd = self { return true @@ -63,8 +93,6 @@ extension PureYAML.Parsing.Event { var mark: PureYAML.Parsing.Mark { switch self { case let .alias(_, mark), - let .documentEnd(mark), - let .documentStart(mark), let .mappingEnd(mark), let .mappingStart(_, _, _, mark), let .scalar(_, _, _, _, mark, _), @@ -73,6 +101,9 @@ extension PureYAML.Parsing.Event { let .streamEnd(mark), let .streamStart(mark): mark + case let .documentEnd(_, mark), + let .documentStart(_, mark): + mark } } diff --git a/Sources/Parsing/EventComposer.swift b/Sources/Parsing/EventComposer.swift index 1a4aac3..319a25c 100644 --- a/Sources/Parsing/EventComposer.swift +++ b/Sources/Parsing/EventComposer.swift @@ -41,7 +41,7 @@ extension PureYAML.Parsing { } return false } - if case let .documentStart(mark)? = current { + if case let .documentStart(_, mark)? = current { throw PureYAML.Parsing.ParseError.unsupportedMultiDocumentStream(line: mark.line) } _ = try expectStreamEnd() @@ -173,7 +173,10 @@ extension PureYAML.Parsing.EventComposer { ) } index += 1 - store(.string(value), anchor: anchor) + if let anchor { + let model = try composeScalar(value, tag: tag, style: style, mark: .start) + store(model, anchor: anchor) + } return ComposedMappingKey( keyNode: .string(value), scalarValue: value, diff --git a/Sources/Parsing/EventStreamComposer.swift b/Sources/Parsing/EventStreamComposer.swift index 597a2dd..f1498e1 100644 --- a/Sources/Parsing/EventStreamComposer.swift +++ b/Sources/Parsing/EventStreamComposer.swift @@ -30,9 +30,9 @@ extension PureYAML.Parsing { didSeeStreamStart = true case .streamEnd: didSeeStreamEnd = true - case let .documentStart(mark): + case let .documentStart(_, mark): try startDocument(mark: mark) - case let .documentEnd(mark): + case let .documentEnd(_, mark): try endDocument(mark: mark) case let .scalar(value, anchor, tag, style, mark, endMark): try consumeScalar(value, anchor: anchor, tag: tag, style: style, marks: (mark, endMark)) @@ -104,7 +104,6 @@ private extension PureYAML.Parsing.EventStreamComposer { } anchors = [:] currentDocumentValue = nil - currentDocumentLocated = nil } mutating func endDocument(mark: PureYAML.Parsing.Mark) throws { @@ -128,8 +127,6 @@ private extension PureYAML.Parsing.EventStreamComposer { ) throws { let model = try scalarParser.composeScalarValue(value, tag: tag, style: style, mark: marks.start) if let anchor { - // Register the resolved node, not the raw text: an alias resolves to the anchored node's - // value, so an empty scalar anchors null and a typed scalar (`&a 42`) anchors that value. anchors[anchor] = model } try complete(.init( @@ -198,7 +195,7 @@ private extension PureYAML.Parsing.EventStreamComposer { guard container.pendingKey == nil else { throw unexpectedEvent(expected: "mapping value", mark: mark) } - let pairs = PureYAML.Parsing.MergeResolution.mergedPairs( + let pairs = mergedPairs( from: container.mergeSources, localPairs: container.localPairs, ) @@ -297,7 +294,7 @@ private extension PureYAML.Parsing.EventStreamComposer { guard !node.sequenceItems.isEmpty else { return try values.map { value in guard case let .mapping(mapping) = value else { - throw PureYAML.Parsing.MergeResolution.invalidMergeValue(mark: node.mark) + throw invalidMergeValue(mark: node.mark) } return mapping.pairs } @@ -305,15 +302,51 @@ private extension PureYAML.Parsing.EventStreamComposer { return try values.enumerated().map { index, value in let mark = node.sequenceItems[index].mark guard case let .mapping(mapping) = value else { - throw PureYAML.Parsing.MergeResolution.invalidMergeValue(mark: mark) + throw invalidMergeValue(mark: mark) } return mapping.pairs } case .bool, .double, .int, .null, .string: - throw PureYAML.Parsing.MergeResolution.invalidMergeValue(mark: node.mark) + throw invalidMergeValue(mark: node.mark) } } + func mergedPairs( + from mergeSources: [[PureYAML.Model.Pair]], + localPairs: [PureYAML.Model.Pair], + ) -> [PureYAML.Model.Pair] { + guard !mergeSources.isEmpty else { + return localPairs + } + + let localKeys = Set(localPairs.map(\.keyNode)) + var inheritedKeys = Set() + var inheritedPairs: [PureYAML.Model.Pair] = [] + for source in mergeSources { + var sourceKeys = Set() + for pair in source { + guard !localKeys.contains(pair.keyNode), + !inheritedKeys.contains(pair.keyNode) + else { + continue + } + inheritedPairs.append(pair) + sourceKeys.insert(pair.keyNode) + } + inheritedKeys.formUnion(sourceKeys) + } + return inheritedPairs + localPairs + } + + func invalidMergeValue( + mark: PureYAML.Parsing.Mark, + ) -> PureYAML.Parsing.ParseError { + PureYAML.Parsing.ParseError.invalidMergeValue( + line: mark.line, + column: mark.column, + ) + } + func unexpectedEvent( expected: String, mark: PureYAML.Parsing.Mark, diff --git a/Sources/Parsing/LibYAML.CharacterClass.swift b/Sources/Parsing/LibYAML.CharacterClass.swift new file mode 100644 index 0000000..b8053a9 --- /dev/null +++ b/Sources/Parsing/LibYAML.CharacterClass.swift @@ -0,0 +1,103 @@ +extension PureYAML.Parsing.LibYAML { + /// Port of libyaml's character-class macros (`IS_*` in `yaml_private.h`). + /// libyaml inspects UTF-8 bytes; this operates on `Unicode.Scalar`, where the + /// multi-byte line breaks NEL (`U+0085`), LS (`U+2028`), and PS (`U+2029`) are + /// single scalars. End of input is `nil`, which is libyaml's `\0` sentinel, so + /// `isZ(nil)` is true and every other predicate is false for `nil`. + enum CharacterClass { + /// `IS_Z`: the end of the input (libyaml's `\0`). + static func isZ(_ scalar: Unicode.Scalar?) -> Bool { + scalar == nil + } + + /// `IS_SPACE`. + static func isSpace(_ scalar: Unicode.Scalar?) -> Bool { + scalar == " " + } + + /// `IS_TAB`. + static func isTab(_ scalar: Unicode.Scalar?) -> Bool { + scalar == "\t" + } + + /// `IS_BLANK`: space or tab. + static func isBlank(_ scalar: Unicode.Scalar?) -> Bool { + isSpace(scalar) || isTab(scalar) + } + + /// `IS_BREAK`: CR, LF, NEL, LS, or PS. + static func isBreak(_ scalar: Unicode.Scalar?) -> Bool { + switch scalar { + case "\r", "\n", "\u{85}", "\u{2028}", "\u{2029}": true + default: false + } + } + + /// `IS_BREAKZ`: a line break or the end of input. + static func isBreakZ(_ scalar: Unicode.Scalar?) -> Bool { + isBreak(scalar) || isZ(scalar) + } + + /// `IS_SPACEZ`: a space, a line break, or the end of input. + static func isSpaceZ(_ scalar: Unicode.Scalar?) -> Bool { + isSpace(scalar) || isBreakZ(scalar) + } + + /// `IS_BLANKZ`: blank (space or tab), a line break, or the end of input. + static func isBlankZ(_ scalar: Unicode.Scalar?) -> Bool { + isBlank(scalar) || isBreakZ(scalar) + } + + /// A flow collection indicator (`,`, `[`, `]`, `{`, `}`); the YAML + /// `c-flow-indicator` set excluded from `ns-plain-safe` in flow context. + static func isFlowIndicator(_ scalar: Unicode.Scalar?) -> Bool { + switch scalar { + case ",", "[", "]", "{", "}": true + default: false + } + } + + /// `IS_DIGIT`. + static func isDigit(_ scalar: Unicode.Scalar?) -> Bool { + guard let scalar else { return false } + return scalar >= "0" && scalar <= "9" + } + + /// `IS_ALPHA`: a digit, ASCII letter, `_`, or `-` (the directive, anchor, + /// and tag-handle name characters). + static func isAlpha(_ scalar: Unicode.Scalar?) -> Bool { + guard let scalar else { return false } + return (scalar >= "0" && scalar <= "9") + || (scalar >= "A" && scalar <= "Z") + || (scalar >= "a" && scalar <= "z") + || scalar == "_" + || scalar == "-" + } + + /// `IS_HEX`: a hexadecimal digit. + static func isHex(_ scalar: Unicode.Scalar?) -> Bool { + guard let scalar else { return false } + return (scalar >= "0" && scalar <= "9") + || (scalar >= "A" && scalar <= "F") + || (scalar >= "a" && scalar <= "f") + } + + /// `IS_ASCII`. + static func isASCII(_ scalar: Unicode.Scalar?) -> Bool { + guard let scalar else { return false } + return scalar.value <= 0x7F + } + + /// `IS_PRINTABLE`: the YAML `c-printable` set. + static func isPrintable(_ scalar: Unicode.Scalar?) -> Bool { + guard let scalar else { return false } + let value = scalar.value + return value == 0x09 || value == 0x0A || value == 0x0D + || (value >= 0x20 && value <= 0x7E) + || value == 0x85 + || (value >= 0xA0 && value <= 0xD7FF) + || (value >= 0xE000 && value <= 0xFFFD) + || (value >= 0x10000 && value <= 0x10FFFF) + } + } +} diff --git a/Sources/Parsing/LibYAML.IndentEngine.swift b/Sources/Parsing/LibYAML.IndentEngine.swift new file mode 100644 index 0000000..1ef725f --- /dev/null +++ b/Sources/Parsing/LibYAML.IndentEngine.swift @@ -0,0 +1,85 @@ +extension PureYAML.Parsing.LibYAML { + /// Port of the indentation stack from `yaml_parser_t` plus + /// `yaml_parser_roll_indent` and `yaml_parser_unroll_indent`. libyaml tracks a + /// single `indent` column (the current block collection's indentation, -1 at + /// the document root) and a stack of the enclosing levels. A block collection + /// is opened only when content is strictly more indented than the current + /// level, which is exactly why `- a:` followed by a same-column `b:` keeps `b` + /// a sibling and leaves `a` an empty value. + struct IndentEngine { + /// `parser->indent`. -1 at the document root, matching libyaml. + private(set) var indent = -1 + /// `parser->indents`, the stack of enclosing indentation levels. + private(set) var indents: [Int] = [] + /// `parser->flow_level`; indentation is inert inside flow collections. + var flowLevel = 0 + /// The token queue (`parser->tokens`) the engine appends to or, for + /// `roll_indent`, inserts a start token into at a recorded position. + private(set) var tokens: [Token] = [] + /// `parser->tokens_parsed`, the count already dequeued, used to turn an + /// absolute token number into an index into the live queue. + var tokensParsed = 0 + + /// Port of `yaml_parser_roll_indent`. In flow context it does nothing. + /// When the column is greater than the current indent, it pushes the + /// current indent, adopts the new column, and emits the block start token. + /// `number == -1` appends; otherwise the token is inserted at the recorded + /// queue position so a `BLOCK-MAPPING-START` precedes a simple key that was + /// already queued. + mutating func rollIndent( + column: Int, + number: Int, + type: TokenType, + mark: PureYAML.Parsing.Mark, + ) { + if flowLevel != 0 { + return + } + if indent < column { + indents.append(indent) + indent = column + let token = Token(type: type, startMark: mark, endMark: mark) + if number == -1 { + tokens.append(token) + } else { + tokens.insert(token, at: number - tokensParsed) + } + } + } + + /// Port of `yaml_parser_unroll_indent`. In flow context it does nothing. + /// While the current indent is deeper than the column, it emits a + /// `BLOCK-END` and pops the enclosing level, closing every block collection + /// that the dedent ends. + mutating func unrollIndent(column: Int, mark: PureYAML.Parsing.Mark) { + if flowLevel != 0 { + return + } + while indent > column { + tokens.append(Token(type: .blockEnd, startMark: mark, endMark: mark)) + indent = indents.removeLast() + } + } + + /// `ENQUEUE`: append a token to the queue. + mutating func enqueue(_ token: Token) { + tokens.append(token) + } + + /// `QUEUE_INSERT`: insert a token at an absolute token number, used to + /// splice a `KEY` token in front of a node already queued. + mutating func insert(_ token: Token, atTokenNumber number: Int) { + tokens.insert(token, at: number - tokensParsed) + } + + /// Dequeue the front token, advancing `tokensParsed` like libyaml's + /// `yaml_parser_scan` does when it hands a token to the parser. + mutating func dequeue() -> Token? { + guard !tokens.isEmpty else { + return nil + } + tokensParsed += 1 + return tokens.removeFirst() + } + } +} diff --git a/Sources/Parsing/LibYAML.NodeProperties.swift b/Sources/Parsing/LibYAML.NodeProperties.swift new file mode 100644 index 0000000..2331a9b --- /dev/null +++ b/Sources/Parsing/LibYAML.NodeProperties.swift @@ -0,0 +1,12 @@ +extension PureYAML.Parsing.LibYAML { + /// The anchor and tag scanned ahead of a node's content, with the marks needed + /// for events and tag-resolution errors. Mirrors the locals in + /// `yaml_parser_parse_node`. + struct NodeProperties { + var anchor: String? + var tagHandle: String? + var tagSuffix: String? + var startMark: PureYAML.Parsing.Mark + var tagMark: PureYAML.Parsing.Mark + } +} diff --git a/Sources/Parsing/LibYAML.Parser.Block.swift b/Sources/Parsing/LibYAML.Parser.Block.swift new file mode 100644 index 0000000..2f92623 --- /dev/null +++ b/Sources/Parsing/LibYAML.Parser.Block.swift @@ -0,0 +1,109 @@ +extension PureYAML.Parsing.LibYAML.Parser { + /// Port of `yaml_parser_parse_block_sequence_entry`. + mutating func parseBlockSequenceEntry(first: Bool) throws -> Event { + if first { + marks.append(peekToken().startMark) + skipToken() + } + let token = peekToken() + if case .blockEntry = token.type { + let mark = token.endMark + skipToken() + let next = peekToken() + if !isBlockEntry(next), !isBlockEnd(next) { + states.append(.blockSequenceEntry) + return try parseNode(block: true, indentlessSequence: false) + } + state = .blockSequenceEntry + return processEmptyScalar(at: mark) + } + if case .blockEnd = token.type { + state = states.removeLast() + _ = marks.popLast() + skipToken() + return .sequenceEnd(mark: token.startMark) + } + throw ParserError( + context: "while parsing a block collection", + problem: "did not find expected '-' indicator", + mark: marks.popLast() ?? token.startMark, + ) + } + + /// Port of `yaml_parser_parse_indentless_sequence_entry`. The closing token + /// belongs to the enclosing collection, so the SEQUENCE-END is emitted without + /// consuming it. + mutating func parseIndentlessSequenceEntry() throws -> Event { + let token = peekToken() + guard case .blockEntry = token.type else { + state = states.removeLast() + return .sequenceEnd(mark: token.startMark) + } + let mark = token.endMark + skipToken() + let next = peekToken() + if !isBlockEntry(next), !isKey(next), !isValue(next), !isBlockEnd(next) { + states.append(.indentlessSequenceEntry) + return try parseNode(block: true, indentlessSequence: false) + } + state = .indentlessSequenceEntry + return processEmptyScalar(at: mark) + } + + /// Port of `yaml_parser_parse_block_mapping_key`. + mutating func parseBlockMappingKey(first: Bool) throws -> Event { + if first { + marks.append(peekToken().startMark) + skipToken() + } + let token = peekToken() + if case .key = token.type { + let mark = token.endMark + skipToken() + let next = peekToken() + if !isKey(next), !isValue(next), !isBlockEnd(next) { + states.append(.blockMappingValue) + return try parseNode(block: true, indentlessSequence: true) + } + state = .blockMappingValue + return processEmptyScalar(at: mark) + } + if case .blockEnd = token.type { + state = states.removeLast() + _ = marks.popLast() + skipToken() + return .mappingEnd(mark: token.startMark) + } + // YAML 1.2 permits an empty (null) key: a VALUE indicator with no + // preceding key denotes a mapping entry whose key is empty. libyaml + // rejects this here; instead emit the empty scalar key and leave the + // VALUE token for `parseBlockMappingValue` to consume. + if case .value = token.type { + state = .blockMappingValue + return processEmptyScalar(at: token.startMark) + } + throw ParserError( + context: "while parsing a block mapping", + problem: "did not find expected key", + mark: marks.popLast() ?? token.startMark, + ) + } + + /// Port of `yaml_parser_parse_block_mapping_value`. + mutating func parseBlockMappingValue() throws -> Event { + let token = peekToken() + guard case .value = token.type else { + state = .blockMappingKey + return processEmptyScalar(at: token.startMark) + } + let mark = token.endMark + skipToken() + let next = peekToken() + if !isKey(next), !isValue(next), !isBlockEnd(next) { + states.append(.blockMappingKey) + return try parseNode(block: true, indentlessSequence: true) + } + state = .blockMappingKey + return processEmptyScalar(at: mark) + } +} diff --git a/Sources/Parsing/LibYAML.Parser.Directives.swift b/Sources/Parsing/LibYAML.Parser.Directives.swift new file mode 100644 index 0000000..5b02fb2 --- /dev/null +++ b/Sources/Parsing/LibYAML.Parser.Directives.swift @@ -0,0 +1,70 @@ +extension PureYAML.Parsing.LibYAML.Parser { + /// The implied tag handles, mirroring libyaml's `default_tag_directives`. + private var defaultTagDirectives: [(handle: String, prefix: String)] { + [("!", "!"), ("!!", "tag:yaml.org,2002:")] + } + + /// Port of `yaml_parser_process_directives`: consume the `%YAML` and `%TAG` + /// directive tokens at the head of a document, validating the version and + /// recording the tag handles, then install the default tag handles. The + /// version is checked against a local so a duplicate `%YAML` is rejected. + mutating func processDirectives() throws { + var version: (major: Int, minor: Int)? + var token = peekToken() + while true { + if case let .versionDirective(major, minor) = token.type { + try recordVersion(major: major, minor: minor, into: &version, mark: token.startMark) + } else if case let .tagDirective(handle, prefix) = token.type { + try appendTagDirective(handle: handle, prefix: prefix, allowDuplicates: false, mark: token.startMark) + } else if case .reservedDirective = token.type { + // A reserved directive is ignored (YAML 1.2 §6.8.1) but still + // consumed here so the explicit-document path requires a `---`. + } else { + break + } + skipToken() + token = peekToken() + } + for directive in defaultTagDirectives { + try appendTagDirective(handle: directive.handle, prefix: directive.prefix, allowDuplicates: true, mark: token.startMark) + } + } + + private mutating func recordVersion(major: Int, minor: Int, into version: inout (major: Int, minor: Int)?, mark: Mark) throws { + guard version == nil else { + throw ParserError(context: nil, problem: "found duplicate %YAML directive", mark: mark) + } + // YAML 1.2 §6.8.1: a document whose major version is 1 is parsed even when + // the minor version is newer than 1.2 (with a warning), rather than + // libyaml's hard rejection of any minor other than 1 or 2. + guard major == 1 else { + throw ParserError(context: nil, problem: "found incompatible YAML document", mark: mark) + } + version = (major, minor) + } + + /// Port of `yaml_parser_append_tag_directive`: append a handle/prefix mapping, + /// rejecting a redefinition unless duplicates are allowed (the defaults are). + mutating func appendTagDirective(handle: String, prefix: String, allowDuplicates: Bool, mark: Mark) throws { + if tagDirectives.contains(where: { $0.handle == handle }) { + if allowDuplicates { + return + } + throw ParserError(context: nil, problem: "found duplicate %TAG directive", mark: mark) + } + tagDirectives.append((handle, prefix)) + } + + /// Port of the tag-resolution block in `yaml_parser_parse_node`: an empty + /// handle means the suffix is a verbatim tag; otherwise substitute the handle's + /// registered prefix, failing on an undefined handle. + func resolveTag(handle: String, suffix: String, startMark _: Mark, tagMark: Mark) throws -> String { + guard !handle.isEmpty else { + return suffix + } + guard let directive = tagDirectives.first(where: { $0.handle == handle }) else { + throw ParserError(context: "while parsing a node", problem: "found undefined tag handle", mark: tagMark) + } + return directive.prefix + suffix + } +} diff --git a/Sources/Parsing/LibYAML.Parser.Document.swift b/Sources/Parsing/LibYAML.Parser.Document.swift new file mode 100644 index 0000000..6abe53d --- /dev/null +++ b/Sources/Parsing/LibYAML.Parser.Document.swift @@ -0,0 +1,112 @@ +extension PureYAML.Parsing.LibYAML.Parser { + /// Port of `yaml_parser_parse_stream_start`. + mutating func parseStreamStart() throws -> Event { + let token = peekToken() + guard case .streamStart = token.type else { + throw ParserError(context: nil, problem: "did not find expected ", mark: token.startMark) + } + state = .implicitDocumentStart + skipToken() + return .streamStart(mark: token.startMark) + } + + /// Port of `yaml_parser_parse_document_start`, extended for YAML 1.2: stray + /// `...` markers are skipped, then a bare document is opened when one is allowed + /// (the first document or after an explicit `...`), an explicit document is + /// opened after directives and a `---`, or STREAM-END is emitted. libyaml only + /// allows a bare document as the very first one. + mutating func parseDocumentStart() throws -> Event { + var token = peekToken() + while case .documentEnd = token.type { + skipToken() + token = peekToken() + } + // Directives apply to the document that follows, so the previous document + // must be closed with an explicit `...` end marker before them. After an + // implicit end (`allowBareDocument` is false) a directive is an error. + if isDirective(token), !allowBareDocument { + throw ParserError( + context: nil, + problem: "directives require a preceding document end marker", + mark: token.startMark, + ) + } + if allowBareDocument, !isDirectiveOrBoundary(token) { + try processDirectives() + states.append(.documentEnd) + state = .blockNode + return .documentStart(explicit: false, mark: token.startMark) + } + if case .streamEnd = token.type { + state = .end + skipToken() + return .streamEnd(mark: token.startMark) + } + return try openExplicitDocument(startMark: token.startMark) + } + + /// The explicit-document branch: directives then a required `---`. + private mutating func openExplicitDocument(startMark: Mark) throws -> Event { + try processDirectives() + let token = peekToken() + guard case .documentStart = token.type else { + throw ParserError(context: nil, problem: "did not find expected ", mark: token.startMark) + } + states.append(.documentEnd) + state = .documentContent + skipToken() + return .documentStart(explicit: true, mark: startMark) + } + + /// Port of `yaml_parser_parse_document_content`: an empty scalar stands in for + /// a document with no node, otherwise parse the root node. + mutating func parseDocumentContent() throws -> Event { + let token = peekToken() + if isDirectiveOrBoundary(token) || isDocumentEnd(token) { + state = states.removeLast() + return processEmptyScalar(at: token.startMark) + } + return try parseNode(block: true, indentlessSequence: false) + } + + /// Port of `yaml_parser_parse_document_end`: reset the per-document tag + /// directives and emit DOCUMENT-END, explicit only when `...` was present. + mutating func parseDocumentEnd() throws -> Event { + let token = peekToken() + var explicit = false + if case .documentEnd = token.type { + skipToken() + explicit = true + } + tagDirectives.removeAll() + // A bare document may follow only an explicit `...` end marker. + allowBareDocument = explicit + state = .documentStart + return .documentEnd(explicit: explicit, mark: token.startMark) + } + + private func isDirectiveOrBoundary(_ token: Token) -> Bool { + switch token.type { + case .versionDirective, .tagDirective, .reservedDirective, .documentStart, .streamEnd: + true + default: + false + } + } + + private func isDirective(_ token: Token) -> Bool { + switch token.type { + case .versionDirective, .tagDirective, .reservedDirective: + true + default: + false + } + } + + private func isDocumentEnd(_ token: Token) -> Bool { + if case .documentEnd = token.type { + return true + } + return false + } +} diff --git a/Sources/Parsing/LibYAML.Parser.Flow.swift b/Sources/Parsing/LibYAML.Parser.Flow.swift new file mode 100644 index 0000000..db65a2d --- /dev/null +++ b/Sources/Parsing/LibYAML.Parser.Flow.swift @@ -0,0 +1,157 @@ +extension PureYAML.Parsing.LibYAML.Parser { + /// Port of `yaml_parser_parse_flow_sequence_entry`. A `?` key inside a flow + /// sequence opens a single-pair flow mapping. + mutating func parseFlowSequenceEntry(first: Bool) throws -> Event { + if first { + marks.append(peekToken().startMark) + skipToken() + } + var token = peekToken() + if !isFlowSequenceEnd(token) { + if !first { + guard isFlowEntry(token) else { + throw ParserError( + context: "while parsing a flow sequence", + problem: "did not find expected ',' or ']'", + mark: marks.popLast() ?? token.startMark, + ) + } + skipToken() + token = peekToken() + } + if isKey(token) { + state = .flowSequenceEntryMappingKey + skipToken() + return .mappingStart(anchor: nil, tag: nil, style: .flow, mark: token.startMark) + } + if isValue(token) { + // A leading `:` opens a single-pair mapping with an empty key + // (`[ : v ]`). Keep the VALUE token for the mapping-key state. + state = .flowSequenceEntryMappingKey + return .mappingStart(anchor: nil, tag: nil, style: .flow, mark: token.startMark) + } + if !isFlowSequenceEnd(token) { + states.append(.flowSequenceEntry) + return try parseNode(block: false, indentlessSequence: false) + } + } + state = states.removeLast() + _ = marks.popLast() + skipToken() + return .sequenceEnd(mark: token.startMark) + } + + /// Port of `yaml_parser_parse_flow_sequence_entry_mapping_key`. + mutating func parseFlowSequenceEntryMappingKey() throws -> Event { + let token = peekToken() + if !isValue(token), !isFlowEntry(token), !isFlowSequenceEnd(token) { + states.append(.flowSequenceEntryMappingValue) + return try parseNode(block: false, indentlessSequence: false) + } + // An empty key: leave a VALUE token for the value state to consume (so the + // value is parsed); a closing `]` ends the pair with an empty value too. + if isValue(token) || isFlowSequenceEnd(token) { + state = .flowSequenceEntryMappingValue + return processEmptyScalar(at: token.startMark) + } + let mark = token.endMark + skipToken() + state = .flowSequenceEntryMappingValue + return processEmptyScalar(at: mark) + } + + /// Port of `yaml_parser_parse_flow_sequence_entry_mapping_value`. + mutating func parseFlowSequenceEntryMappingValue() throws -> Event { + var token = peekToken() + if isValue(token) { + skipToken() + token = peekToken() + if !isFlowEntry(token), !isFlowSequenceEnd(token) { + states.append(.flowSequenceEntryMappingEnd) + return try parseNode(block: false, indentlessSequence: false) + } + } + state = .flowSequenceEntryMappingEnd + return processEmptyScalar(at: token.startMark) + } + + /// Port of `yaml_parser_parse_flow_sequence_entry_mapping_end`. + mutating func parseFlowSequenceEntryMappingEnd() throws -> Event { + let token = peekToken() + state = .flowSequenceEntry + return .mappingEnd(mark: token.startMark) + } + + /// Port of `yaml_parser_parse_flow_mapping_key`. + mutating func parseFlowMappingKey(first: Bool) throws -> Event { + if first { + marks.append(peekToken().startMark) + skipToken() + } + var token = peekToken() + if !isFlowMappingEnd(token) { + if !first { + guard isFlowEntry(token) else { + throw ParserError( + context: "while parsing a flow mapping", + problem: "did not find expected ',' or '}'", + mark: marks.popLast() ?? token.startMark, + ) + } + skipToken() + token = peekToken() + } + if isKey(token) { + return try flowMappingKeyEvent() + } + // YAML 1.2 permits an empty (null) key in a flow mapping: a `:` with + // no preceding key denotes an entry whose key is empty. libyaml hands + // the VALUE token to `parse_node` and fails; instead emit the empty + // scalar key and let `parseFlowMappingValue` consume the indicator. + if isValue(token) { + state = .flowMappingValue + return processEmptyScalar(at: token.startMark) + } + if !isFlowMappingEnd(token) { + states.append(.flowMappingEmptyValue) + return try parseNode(block: false, indentlessSequence: false) + } + } + state = states.removeLast() + _ = marks.popLast() + skipToken() + return .mappingEnd(mark: token.startMark) + } + + /// The KEY branch of `parse_flow_mapping_key`: parse the key node, or an empty + /// scalar when a value/entry/end follows the `?` immediately. + private mutating func flowMappingKeyEvent() throws -> Event { + skipToken() + let token = peekToken() + if !isValue(token), !isFlowEntry(token), !isFlowMappingEnd(token) { + states.append(.flowMappingValue) + return try parseNode(block: false, indentlessSequence: false) + } + state = .flowMappingValue + return processEmptyScalar(at: token.startMark) + } + + /// Port of `yaml_parser_parse_flow_mapping_value`. + mutating func parseFlowMappingValue(empty: Bool) throws -> Event { + var token = peekToken() + if empty { + state = .flowMappingKey + return processEmptyScalar(at: token.startMark) + } + if isValue(token) { + skipToken() + token = peekToken() + if !isFlowEntry(token), !isFlowMappingEnd(token) { + states.append(.flowMappingKey) + return try parseNode(block: false, indentlessSequence: false) + } + } + state = .flowMappingKey + return processEmptyScalar(at: token.startMark) + } +} diff --git a/Sources/Parsing/LibYAML.Parser.Helpers.swift b/Sources/Parsing/LibYAML.Parser.Helpers.swift new file mode 100644 index 0000000..5f65f0a --- /dev/null +++ b/Sources/Parsing/LibYAML.Parser.Helpers.swift @@ -0,0 +1,50 @@ +extension PureYAML.Parsing.LibYAML.Parser { + func isBlockEntry(_ token: Token) -> Bool { + if case .blockEntry = token.type { + return true + } + return false + } + + func isBlockEnd(_ token: Token) -> Bool { + if case .blockEnd = token.type { + return true + } + return false + } + + func isKey(_ token: Token) -> Bool { + if case .key = token.type { + return true + } + return false + } + + func isValue(_ token: Token) -> Bool { + if case .value = token.type { + return true + } + return false + } + + func isFlowEntry(_ token: Token) -> Bool { + if case .flowEntry = token.type { + return true + } + return false + } + + func isFlowSequenceEnd(_ token: Token) -> Bool { + if case .flowSequenceEnd = token.type { + return true + } + return false + } + + func isFlowMappingEnd(_ token: Token) -> Bool { + if case .flowMappingEnd = token.type { + return true + } + return false + } +} diff --git a/Sources/Parsing/LibYAML.Parser.Node.swift b/Sources/Parsing/LibYAML.Parser.Node.swift new file mode 100644 index 0000000..edf9e74 --- /dev/null +++ b/Sources/Parsing/LibYAML.Parser.Node.swift @@ -0,0 +1,99 @@ +extension PureYAML.Parsing.LibYAML.Parser { + typealias NodeProperties = PureYAML.Parsing.LibYAML.NodeProperties + + /// Port of `yaml_parser_parse_node`. An ALIAS is emitted directly; otherwise + /// the node's anchor/tag properties are consumed, the tag is resolved, and the + /// content token selects a scalar, a flow/block collection start, or an empty + /// scalar standing in for a property-only node. + mutating func parseNode(block: Bool, indentlessSequence: Bool) throws -> Event { + let token = peekToken() + if case let .alias(name) = token.type { + state = states.removeLast() + skipToken() + return .alias(anchor: name, mark: token.startMark) + } + let props = consumeNodeProperties() + let tag = try props.tagHandle.map { + try resolveTag(handle: $0, suffix: props.tagSuffix ?? "", startMark: props.startMark, tagMark: props.tagMark) + } + return try dispatchNodeContent(block: block, indentlessSequence: indentlessSequence, props: props, tag: tag) + } + + /// Consume `properties ::= TAG ANCHOR? | ANCHOR TAG?` ahead of the content. + private mutating func consumeNodeProperties() -> NodeProperties { + var token = peekToken() + var props = NodeProperties(anchor: nil, tagHandle: nil, tagSuffix: nil, startMark: token.startMark, tagMark: token.startMark) + if case let .anchor(name) = token.type { + props.anchor = name + skipToken() + token = peekToken() + if case let .tag(handle, suffix) = token.type { + props.tagHandle = handle + props.tagSuffix = suffix + props.tagMark = token.startMark + skipToken() + } + } else if case let .tag(handle, suffix) = token.type { + props.tagHandle = handle + props.tagSuffix = suffix + props.tagMark = token.startMark + skipToken() + token = peekToken() + if case let .anchor(name) = token.type { + props.anchor = name + skipToken() + } + } + return props + } + + /// Select the event for the content token following a node's properties. + private mutating func dispatchNodeContent(block: Bool, indentlessSequence: Bool, props: NodeProperties, tag: String?) throws -> Event { + let token = peekToken() + if indentlessSequence, case .blockEntry = token.type { + state = .indentlessSequenceEntry + return .sequenceStart(anchor: props.anchor, tag: tag, style: .block, mark: props.startMark) + } + if let event = contentEvent(token: token, block: block, props: props, tag: tag) { + return event + } + return try emptyNodeOrError(token: token, block: block, props: props, tag: tag) + } + + /// A scalar or a flow/block collection start, or nil if the token is neither. + private mutating func contentEvent(token: Token, block: Bool, props: NodeProperties, tag: String?) -> Event? { + switch token.type { + case let .scalar(value, style): + state = states.removeLast() + skipToken() + return .scalar(value: value, anchor: props.anchor, tag: tag, style: style, mark: props.startMark, endMark: token.endMark) + case .flowSequenceStart: + state = .flowSequenceFirstEntry + return .sequenceStart(anchor: props.anchor, tag: tag, style: .flow, mark: props.startMark) + case .flowMappingStart: + state = .flowMappingFirstKey + return .mappingStart(anchor: props.anchor, tag: tag, style: .flow, mark: props.startMark) + case .blockSequenceStart where block: + state = .blockSequenceFirstEntry + return .sequenceStart(anchor: props.anchor, tag: tag, style: .block, mark: props.startMark) + case .blockMappingStart where block: + state = .blockMappingFirstKey + return .mappingStart(anchor: props.anchor, tag: tag, style: .block, mark: props.startMark) + default: + return nil + } + } + + /// An empty scalar when the node carried only properties, else a parse error. + private mutating func emptyNodeOrError(token: Token, block: Bool, props: NodeProperties, tag: String?) throws -> Event { + if props.anchor != nil || tag != nil { + state = states.removeLast() + return .scalar(value: "", anchor: props.anchor, tag: tag, style: .plain, mark: props.startMark, endMark: props.startMark) + } + throw ParserError( + context: block ? "while parsing a block node" : "while parsing a flow node", + problem: "did not find expected node content", + mark: token.startMark, + ) + } +} diff --git a/Sources/Parsing/LibYAML.Parser.swift b/Sources/Parsing/LibYAML.Parser.swift new file mode 100644 index 0000000..a84caa4 --- /dev/null +++ b/Sources/Parsing/LibYAML.Parser.swift @@ -0,0 +1,148 @@ +extension PureYAML.Parsing.LibYAML { + /// A faithful port of libyaml's `parser.c`: a one-event-at-a-time state + /// machine that consumes the scanner's token stream and produces the YAML + /// event stream. The token queue is materialized up front by the scanner, so + /// `peekToken`/`skipToken` index into a fixed array rather than pulling lazily, + /// which is equivalent because simple-key resolution lives entirely in the + /// scanner. + struct Parser { + let tokens: [Token] + var cursor = 0 + var state: ParserState = .streamStart + var states: [ParserState] = [] + var marks: [Mark] = [] + var tagDirectives: [(handle: String, prefix: String)] = [] + /// Whether a bare (implicit) document may begin here: true for the first + /// document and after an explicit `...` end marker, false otherwise. YAML + /// 1.2 allows a bare document to follow `...`, which libyaml rejects. + var allowBareDocument = true + + init(_ input: String = "") throws { + var scanner = Scanner(input) + tokens = try scanner.scanAll() + } + + init(tokens: [Token]) { + self.tokens = tokens + } + + /// Drive the state machine until STREAM-END, collecting every event. + mutating func parse() throws -> [Event] { + var events: [Event] = [] + while state != .end { + try events.append(stateMachine()) + } + return events + } + + /// The head of the token queue. STREAM-END is always the final token and + /// the machine halts once it has been consumed, so the clamp is never the + /// value actually parsed; it only avoids an out-of-range index. + func peekToken() -> Token { + tokens[min(cursor, tokens.count - 1)] + } + + mutating func skipToken() { + cursor += 1 + } + + /// Port of `yaml_parser_state_machine`: dispatch on the current state. The + /// flat 24-way switch is split into document/block/flow groups to keep each + /// dispatcher's branching within the complexity budget. + mutating func stateMachine() throws -> Event { + switch state { + case .streamStart, .implicitDocumentStart, .documentStart, .documentContent, .documentEnd: + try documentStateMachine() + case .blockNode, .blockNodeOrIndentlessSequence, .flowNode, + .blockSequenceFirstEntry, .blockSequenceEntry, .indentlessSequenceEntry, + .blockMappingFirstKey, .blockMappingKey, .blockMappingValue: + try nodeStateMachine() + case .flowSequenceFirstEntry, .flowSequenceEntry, .flowSequenceEntryMappingKey, + .flowSequenceEntryMappingValue, .flowSequenceEntryMappingEnd, + .flowMappingFirstKey, .flowMappingKey, .flowMappingValue, .flowMappingEmptyValue: + try flowStateMachine() + case .end: + throw endError() + } + } + + private mutating func documentStateMachine() throws -> Event { + switch state { + case .streamStart: + try parseStreamStart() + case .implicitDocumentStart: + try parseDocumentStart() + case .documentStart: + try parseDocumentStart() + case .documentContent: + try parseDocumentContent() + default: + try parseDocumentEnd() + } + } + + private mutating func nodeStateMachine() throws -> Event { + switch state { + case .blockNode: + try parseNode(block: true, indentlessSequence: false) + case .blockNodeOrIndentlessSequence: + try parseNode(block: true, indentlessSequence: true) + case .flowNode: + try parseNode(block: false, indentlessSequence: false) + case .blockSequenceFirstEntry: + try parseBlockSequenceEntry(first: true) + case .blockSequenceEntry: + try parseBlockSequenceEntry(first: false) + case .indentlessSequenceEntry: + try parseIndentlessSequenceEntry() + case .blockMappingFirstKey: + try parseBlockMappingKey(first: true) + case .blockMappingKey: + try parseBlockMappingKey(first: false) + default: + try parseBlockMappingValue() + } + } + + private mutating func flowStateMachine() throws -> Event { + switch state { + case .flowSequenceFirstEntry: + try parseFlowSequenceEntry(first: true) + case .flowSequenceEntry: + try parseFlowSequenceEntry(first: false) + case .flowSequenceEntryMappingKey: + try parseFlowSequenceEntryMappingKey() + case .flowSequenceEntryMappingValue: + try parseFlowSequenceEntryMappingValue() + case .flowSequenceEntryMappingEnd: + try parseFlowSequenceEntryMappingEnd() + case .flowMappingFirstKey: + try parseFlowMappingKey(first: true) + case .flowMappingKey: + try parseFlowMappingKey(first: false) + case .flowMappingValue: + try parseFlowMappingValue(empty: false) + default: + try parseFlowMappingValue(empty: true) + } + } + + private func endError() -> ParserError { + ParserError(context: nil, problem: "parsed past the end of the stream", mark: peekToken().startMark) + } + + /// Port of `yaml_parser_process_empty_scalar`: an empty plain scalar event + /// stands in for an absent node. + func processEmptyScalar(at mark: Mark) -> Event { + .scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: mark, endMark: mark) + } + } +} + +extension PureYAML.Parsing.LibYAML.Parser { + typealias Token = PureYAML.Parsing.LibYAML.Token + typealias Mark = PureYAML.Parsing.Mark + typealias Event = PureYAML.Parsing.Event + typealias ParserError = PureYAML.Parsing.LibYAML.ParserError + typealias ParserState = PureYAML.Parsing.LibYAML.ParserState +} diff --git a/Sources/Parsing/LibYAML.ParserError.swift b/Sources/Parsing/LibYAML.ParserError.swift new file mode 100644 index 0000000..31b1794 --- /dev/null +++ b/Sources/Parsing/LibYAML.ParserError.swift @@ -0,0 +1,10 @@ +extension PureYAML.Parsing.LibYAML { + /// A parser error, mirroring `yaml_parser_set_parser_error[_context]`: an + /// optional context describing the surrounding production, the immediate + /// problem, and the mark where it was detected. + struct ParserError: Error, Equatable { + var context: String? + var problem: String + var mark: PureYAML.Parsing.Mark + } +} diff --git a/Sources/Parsing/LibYAML.ParserState.swift b/Sources/Parsing/LibYAML.ParserState.swift new file mode 100644 index 0000000..4049a1d --- /dev/null +++ b/Sources/Parsing/LibYAML.ParserState.swift @@ -0,0 +1,30 @@ +extension PureYAML.Parsing.LibYAML { + /// The parser state, mirroring `yaml_parser_state_e`. Each case names the + /// production the state machine is in the middle of recognizing. + enum ParserState: Equatable { + case streamStart + case implicitDocumentStart + case documentStart + case documentContent + case documentEnd + case blockNode + case blockNodeOrIndentlessSequence + case flowNode + case blockSequenceFirstEntry + case blockSequenceEntry + case indentlessSequenceEntry + case blockMappingFirstKey + case blockMappingKey + case blockMappingValue + case flowSequenceFirstEntry + case flowSequenceEntry + case flowSequenceEntryMappingKey + case flowSequenceEntryMappingValue + case flowSequenceEntryMappingEnd + case flowMappingFirstKey + case flowMappingKey + case flowMappingValue + case flowMappingEmptyValue + case end + } +} diff --git a/Sources/Parsing/LibYAML.Reader.swift b/Sources/Parsing/LibYAML.Reader.swift new file mode 100644 index 0000000..611af5b --- /dev/null +++ b/Sources/Parsing/LibYAML.Reader.swift @@ -0,0 +1,57 @@ +extension PureYAML.Parsing.LibYAML { + /// Port of libyaml's input buffer and position tracking (the `buffer`/`mark` + /// fields with the `PEEK`, `SKIP`, and `SKIP_LINE` macros). It iterates + /// `Unicode.Scalar`s rather than grapheme clusters so a CR and an LF are + /// distinct, matching libyaml's byte-oriented scanning, and tracks the mark in + /// libyaml's 0-based line and column convention; conversion to the package's + /// 1-based `Mark` happens at token emission during integration. + struct Reader { + private let scalars: [Unicode.Scalar] + private(set) var index = 0 + private(set) var line = 0 + private(set) var column = 0 + + init(_ string: String) { + scalars = Array(string.unicodeScalars) + } + + /// `PEEK_TOKEN` / `CHECK_AT`: the scalar `offset` ahead, or nil past the + /// end (libyaml's `\0`). + func peek(_ offset: Int = 0) -> Unicode.Scalar? { + let position = index + offset + return position < scalars.count ? scalars[position] : nil + } + + var isAtEnd: Bool { + index >= scalars.count + } + + /// The current position. Column is 0-based, as in libyaml. + var mark: PureYAML.Parsing.Mark { + PureYAML.Parsing.Mark(line: line, column: column, index: index) + } + + /// `SKIP`: consume one non-break scalar, advancing the column. + mutating func skip() { + guard index < scalars.count else { + return + } + index += 1 + column += 1 + } + + /// `SKIP_LINE`: consume a line break and start a new line. A CR+LF pair is + /// one break, matching libyaml. + mutating func skipLine() { + if peek() == "\r", peek(1) == "\n" { + index += 2 + } else if CharacterClass.isBreak(peek()) { + index += 1 + } else { + return + } + line += 1 + column = 0 + } + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.Anchor.swift b/Sources/Parsing/LibYAML.Scanner.Anchor.swift new file mode 100644 index 0000000..1df8ba0 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.Anchor.swift @@ -0,0 +1,45 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + + /// Port of `yaml_parser_scan_anchor`, widened to YAML 1.2: an anchor (`&name`) + /// or alias (`*name`) name is `ns-anchor-char+`, i.e. any printable character + /// that is not whitespace, a line break, or a flow indicator (`,[]{}`). libyaml + /// restricts the name to alphanumerics, which rejects Unicode and punctuation + /// anchor names that YAML 1.2 allows. + mutating func scanAnchor(isAnchor: Bool) throws -> PureYAML.Parsing.LibYAML.Token { + let startMark = reader.mark + reader.skip() + var name = "" + while let character = reader.peek(), isAnchorCharacter(character) { + name.unicodeScalars.append(character) + reader.skip() + } + let endMark = reader.mark + guard !name.isEmpty else { + throw PureYAML.Parsing.LibYAML.ScannerError( + context: isAnchor ? "while scanning an anchor" : "while scanning an alias", + problem: "did not find expected alphabetic or numeric character", + mark: startMark, + ) + } + return PureYAML.Parsing.LibYAML.Token( + type: isAnchor ? .anchor(name: name) : .alias(name: name), + startMark: startMark, + endMark: endMark, + ) + } + + /// `ns-anchor-char`: a printable, non-blank, non-break character that is not a + /// flow indicator or the byte-order mark. + private func isAnchorCharacter(_ scalar: Unicode.Scalar) -> Bool { + guard Classify.isPrintable(scalar), !Classify.isBlankZ(scalar), scalar != "\u{FEFF}" else { + return false + } + switch scalar { + case ",", "[", "]", "{", "}": + return false + default: + return true + } + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.BlockScalar.swift b/Sources/Parsing/LibYAML.Scanner.BlockScalar.swift new file mode 100644 index 0000000..28faf61 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.BlockScalar.swift @@ -0,0 +1,205 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + + /// The accumulation state for `scan_block_scalar`. + private struct BlockState { + var string = "" + var leadingBreak = "" + var trailingBreaks = "" + var leadingBlank = false + } + + /// Port of `yaml_parser_scan_block_scalar`. Scans a literal (`|`) or folded + /// (`>`) block scalar: parses the chomping (`+`/`-`) and indentation indicators + /// from the header, auto-detects the indentation if not given, then folds the + /// content (literal keeps breaks, folded joins equally-indented non-empty lines + /// with a space) and applies clip/strip/keep chomping to the trailing breaks. + mutating func scanBlockScalar(literal: Bool) throws -> PureYAML.Parsing.LibYAML.Token { + let startMark = reader.mark + reader.skip() + let header = try readBlockScalarHeader(startMark: startMark) + try consumeBlockHeaderTail(startMark: startMark) + + var endMark = reader.mark + // -1 is the "indentation not yet auto-detected" sentinel. libyaml uses 0, + // but a root-level block scalar legitimately detects indentation 0, so 0 + // must be a representable detected value rather than the sentinel. + var indent = -1 + if header.increment != 0 { + indent = indentEngine.indent >= 0 ? indentEngine.indent + header.increment : header.increment + } + var state = BlockState() + try scanBlockScalarBreaks(indent: &indent, state: &state, startMark: startMark, endMark: &endMark) + + while reader.column == indent, reader.peek() != nil { + // A root block scalar (indent 0) ends at a `---`/`...` document marker + // in column 0. libyaml never needs this because it floors the indent + // at 1, but indent 0 lets the loop reach a column-0 marker line. + if reader.column == 0, documentMarkerAhead() { + break + } + foldBlockLine(&state, literal: literal) + while let character = reader.peek(), !Classify.isBreakZ(character) { + state.string.unicodeScalars.append(character) + reader.skip() + } + state.leadingBreak += readBlockLine() + try scanBlockScalarBreaks(indent: &indent, state: &state, startMark: startMark, endMark: &endMark) + } + + if header.chomping != -1 { + state.string += state.leadingBreak + } + if header.chomping == 1 { + state.string += state.trailingBreaks + } + return PureYAML.Parsing.LibYAML.Token( + type: .scalar(value: state.string, style: literal ? .literal : .folded), + startMark: startMark, + endMark: endMark, + ) + } + + /// Parse the chomping and indentation indicators in either order. + private mutating func readBlockScalarHeader(startMark: PureYAML.Parsing.Mark) throws -> (chomping: Int, increment: Int) { + var chomping = 0 + var increment = 0 + if reader.peek() == "+" || reader.peek() == "-" { + chomping = reader.peek() == "+" ? 1 : -1 + reader.skip() + if Classify.isDigit(reader.peek()) { + increment = try blockIncrement(startMark: startMark) + } + } else if Classify.isDigit(reader.peek()) { + increment = try blockIncrement(startMark: startMark) + if reader.peek() == "+" || reader.peek() == "-" { + chomping = reader.peek() == "+" ? 1 : -1 + reader.skip() + } + } + return (chomping, increment) + } + + private mutating func blockIncrement(startMark: PureYAML.Parsing.Mark) throws -> Int { + if reader.peek() == "0" { + throw blockError("found an indentation indicator equal to 0", startMark) + } + let value = digitValue(reader.peek()) + reader.skip() + return value + } + + /// Eat trailing blanks and a comment to the end of the header line, then the + /// line break. + private mutating func consumeBlockHeaderTail(startMark: PureYAML.Parsing.Mark) throws { + while reader.peek() == " " { + reader.skip() + } + if reader.peek() == "#" { + // A comment needs a preceding space, so `>#` (a `#` adjacent to the + // block scalar indicator) is malformed, not a comment. libyaml accepts it. + if reader.column > 0, let previous = reader.peek(-1), !Classify.isBlank(previous) { + throw blockError("found a comment without a preceding space", startMark) + } + while !Classify.isBreakZ(reader.peek()) { + reader.skip() + } + } + guard Classify.isBreakZ(reader.peek()) else { + throw blockError("did not find expected comment or line break", startMark) + } + if Classify.isBreak(reader.peek()) { + reader.skipLine() + } + } + + /// Port of `yaml_parser_scan_block_scalar_breaks`: eat indentation spaces and + /// blank lines, auto-detecting the indentation level when none was given. + private mutating func scanBlockScalarBreaks(indent: inout Int, state: inout BlockState, startMark: PureYAML.Parsing.Mark, endMark: inout PureYAML.Parsing.Mark) throws { + var maxIndent = 0 + endMark = reader.mark + // A tab is content (or separation) once the column reaches the content + // indentation; it is illegal only while still inside the required + // indentation. During auto-detection the floor is the parent indent + 1. + let tabFloor = indent >= 0 ? indent : max(0, indentEngine.indent + 1) + while true { + let lineStart = reader.column + while indent < 0 || reader.column < indent, reader.peek() == " " { + reader.skip() + } + if reader.column > maxIndent { + maxIndent = reader.column + } + if reader.column < tabFloor, Classify.isTab(reader.peek()) { + throw blockError("found a tab character where an indentation space is expected", startMark) + } + if !Classify.isBreak(reader.peek()) { + // A trailing whitespace-only line that ends at end of input without + // a break still counts as one line break for keep chomping (as the + // test-suite reference does), even with no break byte present. + if reader.peek() == nil, reader.column > lineStart { + state.trailingBreaks += "\n" + } + break + } + state.trailingBreaks += readBlockLine() + endMark = reader.mark + } + // A leading empty line may not be more indented than the first content + // line; libyaml silently detects the deeper indent and drops the content. + if indent < 0, !Classify.isBreakZ(reader.peek()), reader.column < maxIndent { + throw blockError("found a leading empty line more indented than the content", startMark) + } + if indent < 0 { + // Auto-detected indentation. A root-level block scalar has a parent + // indent of -1, so the floor is 0 (allowing column-0 content), not + // libyaml's 1. maxIndent >= 0 keeps the result non-negative. + indent = max(maxIndent, indentEngine.indent + 1) + } + } + + /// Fold the pending breaks at the start of a content line (folded style joins a + /// single break between non-blank lines into a space; otherwise breaks are + /// kept). + private func foldBlockLine(_ state: inout BlockState, literal: Bool) { + let trailingBlank = Classify.isBlank(reader.peek()) + if !literal, state.leadingBreak.first == "\n", !state.leadingBlank, !trailingBlank { + if state.trailingBreaks.isEmpty { + state.string += " " + } + state.leadingBreak = "" + } else { + state.string += state.leadingBreak + state.leadingBreak = "" + } + state.string += state.trailingBreaks + state.trailingBreaks = "" + state.leadingBlank = Classify.isBlank(reader.peek()) + } + + private mutating func readBlockLine() -> String { + reader.skipLine() + return "\n" + } + + /// Whether a `---` or `...` document marker (three repeats then a blank, break, + /// or end of input) starts at the current position. + private func documentMarkerAhead() -> Bool { + let first = reader.peek() + guard first == "-" || first == "." else { + return false + } + return reader.peek(1) == first && reader.peek(2) == first && Classify.isBlankZ(reader.peek(3)) + } + + private func digitValue(_ scalar: Unicode.Scalar?) -> Int { + guard let scalar, scalar >= "0", scalar <= "9" else { + return 0 + } + return Int(scalar.value - Unicode.Scalar("0").value) + } + + private func blockError(_ problem: String, _ mark: PureYAML.Parsing.Mark) -> PureYAML.Parsing.LibYAML.ScannerError { + PureYAML.Parsing.LibYAML.ScannerError(context: "while scanning a block scalar", problem: problem, mark: mark) + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.Directive.swift b/Sources/Parsing/LibYAML.Scanner.Directive.swift new file mode 100644 index 0000000..f289784 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.Directive.swift @@ -0,0 +1,153 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + private typealias Token = PureYAML.Parsing.LibYAML.Token + private typealias Mark = PureYAML.Parsing.Mark + + /// The longest version number libyaml accepts (`MAX_NUMBER_LENGTH`). + private var maxVersionNumberLength: Int { + 9 + } + + /// Port of `yaml_parser_fetch_directive`: reset the indentation and simple keys, + /// then scan a `%YAML` or `%TAG` directive token. + mutating func fetchDirective() throws { + indentEngine.unrollIndent(column: -1, mark: reader.mark) + try removeSimpleKey() + simpleKeyAllowed = false + let token = try scanDirective() + indentEngine.enqueue(token) + } + + /// Port of `yaml_parser_scan_directive`, extended to YAML 1.2 §6.8.1: a `%YAML` + /// or `%TAG` directive produces its token; any other (reserved) directive is + /// ignored with a warning, producing a `reservedDirective` token whose content + /// the parser drops, rather than libyaml's hard rejection. The reserved token + /// still marks the document as a directives document, so it must be followed by + /// a `---`. + private mutating func scanDirective() throws -> Token { + let startMark = reader.mark + reader.skip() + let name = try scanDirectiveName(startMark: startMark) + if name == "YAML" { + let version = try scanVersionDirectiveValue(startMark: startMark) + let token = Token(type: .versionDirective(major: version.major, minor: version.minor), startMark: startMark, endMark: reader.mark) + try consumeDirectiveTail(startMark: startMark) + return token + } + if name == "TAG" { + let value = try scanTagDirectiveValue(startMark: startMark) + let token = Token(type: .tagDirective(handle: value.handle, prefix: value.prefix), startMark: startMark, endMark: reader.mark) + try consumeDirectiveTail(startMark: startMark) + return token + } + skipReservedDirectiveLine() + return Token(type: .reservedDirective, startMark: startMark, endMark: reader.mark) + } + + /// Consume a reserved directive's parameters through the end of the line; the + /// whole line is ignored per YAML 1.2 §6.8.1. + private mutating func skipReservedDirectiveLine() { + while !Classify.isBreakZ(reader.peek()) { + reader.skip() + } + if Classify.isBreak(reader.peek()) { + reader.skipLine() + } + } + + /// Eat trailing blanks and an optional comment, require a line break, eat it. + private mutating func consumeDirectiveTail(startMark: Mark) throws { + while Classify.isBlank(reader.peek()) { + reader.skip() + } + if reader.peek() == "#" { + while !Classify.isBreakZ(reader.peek()) { + reader.skip() + } + } + guard Classify.isBreakZ(reader.peek()) else { + throw directiveError("while scanning a directive", "did not find expected comment or line break", startMark) + } + if Classify.isBreak(reader.peek()) { + reader.skipLine() + } + } + + /// Port of `yaml_parser_scan_directive_name`: the alphanumeric name after `%`, + /// which must be non-empty and followed by a blank or line break. + private mutating func scanDirectiveName(startMark: Mark) throws -> String { + var name = "" + while let character = reader.peek(), Classify.isAlpha(character) { + name.unicodeScalars.append(character) + reader.skip() + } + guard !name.isEmpty else { + throw directiveError("while scanning a directive", "could not find expected directive name", startMark) + } + guard Classify.isBlankZ(reader.peek()) else { + throw directiveError("while scanning a directive", "found unexpected non-alphabetical character", startMark) + } + return name + } + + /// Port of `yaml_parser_scan_version_directive_value`: `major.minor`. + private mutating func scanVersionDirectiveValue(startMark: Mark) throws -> (major: Int, minor: Int) { + while Classify.isBlank(reader.peek()) { + reader.skip() + } + let major = try scanVersionDirectiveNumber(startMark: startMark) + guard reader.peek() == "." else { + throw directiveError("while scanning a %YAML directive", "did not find expected digit or '.' character", startMark) + } + reader.skip() + let minor = try scanVersionDirectiveNumber(startMark: startMark) + // The version must be followed by separation; a comment needs a space + // before its `#`, so `%YAML 1.1#...` (no space) is malformed. libyaml + // accepts it, treating the `#` as an adjacent comment. + guard Classify.isBlankZ(reader.peek()) else { + throw directiveError("while scanning a %YAML directive", "did not find expected digit or '.' character", startMark) + } + return (major, minor) + } + + /// Port of `yaml_parser_scan_version_directive_number`: a bounded run of digits. + private mutating func scanVersionDirectiveNumber(startMark: Mark) throws -> Int { + var value = 0 + var length = 0 + while let character = reader.peek(), Classify.isDigit(character) { + length += 1 + guard length <= maxVersionNumberLength else { + throw directiveError("while scanning a %YAML directive", "found extremely long version number", startMark) + } + value = value * 10 + Int(character.value - Unicode.Scalar("0").value) + reader.skip() + } + guard length > 0 else { + throw directiveError("while scanning a %YAML directive", "did not find expected version number", startMark) + } + return value + } + + /// Port of `yaml_parser_scan_tag_directive_value`: `!handle! prefix`. + private mutating func scanTagDirectiveValue(startMark: Mark) throws -> (handle: String, prefix: String) { + while Classify.isBlank(reader.peek()) { + reader.skip() + } + let handle = try scanTagHandle(directive: true, startMark: startMark) + guard Classify.isBlank(reader.peek()) else { + throw directiveError("while scanning a %TAG directive", "did not find expected whitespace", startMark) + } + while Classify.isBlank(reader.peek()) { + reader.skip() + } + let prefix = try scanTagURI(uriChar: true, directive: true, head: "", startMark: startMark) + guard Classify.isBlankZ(reader.peek()) else { + throw directiveError("while scanning a %TAG directive", "did not find expected whitespace or line break", startMark) + } + return (handle, prefix) + } + + private func directiveError(_ context: String, _ problem: String, _ mark: Mark) -> PureYAML.Parsing.LibYAML.ScannerError { + PureYAML.Parsing.LibYAML.ScannerError(context: context, problem: problem, mark: mark) + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.Fetch.swift b/Sources/Parsing/LibYAML.Scanner.Fetch.swift new file mode 100644 index 0000000..6db7da3 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.Fetch.swift @@ -0,0 +1,361 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + private typealias Token = PureYAML.Parsing.LibYAML.Token + private typealias ScannerError = PureYAML.Parsing.LibYAML.ScannerError + + /// Produce every token for the input, mirroring repeated calls to libyaml's + /// `yaml_parser_fetch_next_token` until STREAM-END. Tokens are never dequeued, + /// so `tokens_parsed` stays 0 and `QUEUE_INSERT` positions are absolute, which + /// matches the simple-key splice. + mutating func scanAll() throws -> [PureYAML.Parsing.LibYAML.Token] { + while !streamEndProduced { + try fetchNextToken() + } + return indentEngine.tokens + } + + /// Port of `yaml_parser_fetch_next_token`: emit STREAM-START first, otherwise + /// skip to the next token, expire stale simple keys, unroll the indentation to + /// the current column, and dispatch on the leading character. Constructs not + /// yet ported throw an explicit error rather than mis-scan. + mutating func fetchNextToken() throws { + if !streamStartProduced { + fetchStreamStart() + return + } + + try scanToNextToken() + try checkFlowContinuationIndent() + mark = reader.mark + try staleSimpleKeys() + indentEngine.unrollIndent(column: reader.column, mark: reader.mark) + mark = reader.mark + try dispatchToken() + } + + /// Dispatch on the leading character: stream end, directives and document + /// markers at column 0, then the indicators. + private mutating func dispatchToken() throws { + let character = reader.peek() + if Classify.isZ(character) { + fetchStreamEnd() + return + } + if reader.column == 0, character == "%" { + try fetchDirective() + return + } + if reader.column == 0, isDocumentMarker("-") { + try fetchDocumentIndicator(.documentStart) + return + } + if reader.column == 0, isDocumentMarker(".") { + try fetchDocumentIndicator(.documentEnd) + return + } + guard let character else { + return + } + try dispatchIndicator(character) + } + + /// Dispatch the block-structure indicators and plain scalars; unported + /// constructs throw an explicit error. + private mutating func dispatchIndicator(_ character: Unicode.Scalar) throws { + if try fetchFlowToken(character) { + return + } + if try fetchNodeToken(character) { + return + } + switch character { + case "-" where Classify.isBlankZ(reader.peek(1)): + try fetchBlockEntry() + case "-" where flowLevel > 0 && Classify.isFlowIndicator(reader.peek(1)): + // Per `ns-plain-first` a `-` begins a plain scalar in flow only when a + // flow-safe character follows; before a flow indicator (`[-]`, `[-,`) + // it cannot start a node. libyaml reads it as the scalar `-`. + throw ScannerError( + context: "while scanning for the next token", + problem: "found unexpected '-' indicator", + mark: reader.mark, + ) + case "?" where Classify.isBlankZ(reader.peek(1)) || (flowLevel > 0 && Classify.isFlowIndicator(reader.peek(1))): + // In flow context libyaml treats every `?` as a key indicator, but per + // `ns-plain-first` a `?` followed by a flow-safe character (anything but + // whitespace, end, or a flow indicator) begins a plain scalar (`?foo`). + try fetchKey() + case ":" where Classify.isBlankZ(reader.peek(1)) + || (flowLevel > 0 && (Classify.isFlowIndicator(reader.peek(1)) || flowKeyIsJSON)): + // In flow context libyaml makes every `:` a value indicator. Per the + // spec a `:` only ends a node when followed by whitespace, end of + // input, or a flow indicator, except an adjacent `:` after a JSON + // (quoted) key. Otherwise the `:` is plain-scalar content (`:x`). + try fetchValue() + default: + // A plain scalar may begin with any non-blank character; a blank (a + // tab here, since spaces and breaks were already consumed) cannot + // start a token, matching libyaml's final guard in fetch_next_token. + guard !Classify.isBlankZ(character) else { + throw ScannerError( + context: "while scanning for the next token", + problem: "found character that cannot start any token", + mark: reader.mark, + ) + } + try fetchPlainScalar() + } + } + + /// Fetch a flow-collection indicator (`[` `]` `{` `}` `,`); returns false + /// otherwise. + private mutating func fetchFlowToken(_ character: Unicode.Scalar) throws -> Bool { + switch character { + case "[": fetchFlowCollectionStart(.flowSequenceStart) + case "{": fetchFlowCollectionStart(.flowMappingStart) + case "]": try fetchFlowCollectionEnd(.flowSequenceEnd) + case "}": try fetchFlowCollectionEnd(.flowMappingEnd) + case ",": try fetchFlowEntry() + default: return false + } + return true + } + + /// Fetch a quoted scalar, an anchor/alias, or a block scalar; returns false + /// otherwise. + private mutating func fetchNodeToken(_ character: Unicode.Scalar) throws -> Bool { + switch character { + case "'": try fetchFlowScalar(single: true) + case "\"": try fetchFlowScalar(single: false) + case "&": try fetchAnchor(isAnchor: true) + case "*": try fetchAnchor(isAnchor: false) + case "!": try fetchTag() + case "|" where flowLevel == 0: try fetchBlockScalar(literal: true) + case ">" where flowLevel == 0: try fetchBlockScalar(literal: false) + default: return false + } + return true + } + + /// Port of `yaml_parser_fetch_tag`. + private mutating func fetchTag() throws { + mark = reader.mark + try saveSimpleKey() + simpleKeyAllowed = false + let token = try scanTag() + indentEngine.enqueue(token) + } + + /// Port of `yaml_parser_fetch_block_scalar`. + private mutating func fetchBlockScalar(literal: Bool) throws { + try removeSimpleKey() + simpleKeyAllowed = true + let token = try scanBlockScalar(literal: literal) + indentEngine.enqueue(token) + } + + /// Port of `yaml_parser_fetch_flow_scalar`. + private mutating func fetchFlowScalar(single: Bool) throws { + mark = reader.mark + let saved = simpleKeyAllowed + try saveSimpleKey() + // A quoted scalar that became this level's simple key is a JSON node, so a + // later adjacent `:` (no space) still opens its value. + if saved { + simpleKeys[simpleKeys.count - 1].isJSON = true + } + simpleKeyAllowed = false + let token = try scanFlowScalar(single: single) + indentEngine.enqueue(token) + } + + /// Port of `yaml_parser_fetch_anchor`. + private mutating func fetchAnchor(isAnchor: Bool) throws { + mark = reader.mark + try saveSimpleKey() + simpleKeyAllowed = false + let token = try scanAnchor(isAnchor: isAnchor) + indentEngine.enqueue(token) + } + + /// Port of `yaml_parser_fetch_flow_collection_start`. + private mutating func fetchFlowCollectionStart(_ type: PureYAML.Parsing.LibYAML.TokenType) { + // saveSimpleKey cannot throw in flow: a required key needs block context. + let saved = simpleKeyAllowed + try? saveSimpleKey() + // A flow collection is a JSON node, so when it is this level's simple key + // an adjacent `:` after its closing `]`/`}` still opens its value. + if saved { + simpleKeys[simpleKeys.count - 1].isJSON = true + } + increaseFlowLevel(isSequence: type == .flowSequenceStart) + simpleKeyAllowed = true + let startMark = reader.mark + reader.skip() + indentEngine.enqueue(Token(type: type, startMark: startMark, endMark: reader.mark)) + } + + /// Port of `yaml_parser_fetch_flow_collection_end`. + private mutating func fetchFlowCollectionEnd(_ type: PureYAML.Parsing.LibYAML.TokenType) throws { + try removeSimpleKey() + decreaseFlowLevel() + simpleKeyAllowed = false + let startMark = reader.mark + reader.skip() + indentEngine.enqueue(Token(type: type, startMark: startMark, endMark: reader.mark)) + } + + /// Port of `yaml_parser_fetch_flow_entry`. + private mutating func fetchFlowEntry() throws { + try removeSimpleKey() + simpleKeyAllowed = true + let startMark = reader.mark + reader.skip() + indentEngine.enqueue(Token(type: .flowEntry, startMark: startMark, endMark: reader.mark)) + } + + /// Port of `yaml_parser_fetch_stream_start`. + private mutating func fetchStreamStart() { + // indent is already -1 and simpleKeys already holds the block-context slot. + simpleKeyAllowed = true + streamStartProduced = true + indentEngine.enqueue(Token(type: .streamStart, startMark: reader.mark, endMark: reader.mark)) + } + + /// Port of `yaml_parser_fetch_stream_end`. + private mutating func fetchStreamEnd() { + if reader.column != 0 { + // Force a new line in the mark, as libyaml does. + mark = PureYAML.Parsing.Mark(line: reader.line + 1, column: 0, index: reader.index) + } + indentEngine.unrollIndent(column: -1, mark: mark) + // remove_simple_key cannot throw here: a required key would already have + // been resolved before stream end in the block + plain core. + simpleKeys[simpleKeys.count - 1].possible = false + simpleKeyAllowed = false + streamEndProduced = true + indentEngine.enqueue(Token(type: .streamEnd, startMark: mark, endMark: mark)) + } + + /// Port of `yaml_parser_fetch_document_indicator`. + private mutating func fetchDocumentIndicator(_ type: PureYAML.Parsing.LibYAML.TokenType) throws { + indentEngine.unrollIndent(column: -1, mark: reader.mark) + simpleKeys[simpleKeys.count - 1].possible = false + simpleKeyAllowed = false + let startMark = reader.mark + reader.skip() + reader.skip() + reader.skip() + indentEngine.enqueue(Token(type: type, startMark: startMark, endMark: reader.mark)) + if case .documentEnd = type { + // Only whitespace and a comment may follow `...` on its line; a `--- x` + // document start can carry inline content, but `... x` cannot. + while reader.peek() == " " || Classify.isTab(reader.peek()) { + reader.skip() + } + if let next = reader.peek(), next != "#", !Classify.isBreak(next) { + throw ScannerError( + context: "while scanning a document end marker", + problem: "found content after the document end marker", + mark: reader.mark, + ) + } + } + } + + /// Port of `yaml_parser_fetch_block_entry`. + private mutating func fetchBlockEntry() throws { + if tabbedSeparation { + throw tabIndentationError() + } + // A block sequence must begin its own line. A `-` mid-line after a mapping + // value (`key: - a`) or a node property (`&a - x`) is invalid, but a `-` + // after another `-` is a valid compact sequence (`- - a`). libyaml accepts + // all three. + if flowLevel == 0, !crossedLineBreak, lastTokenForbidsInlineSequence() { + throw ScannerError( + context: "while scanning a node", + problem: "found a block sequence on the same line as an earlier node", + mark: reader.mark, + ) + } + if flowLevel == 0 { + indentEngine.rollIndent(column: reader.column, number: -1, type: .blockSequenceStart, mark: reader.mark) + } + simpleKeys[simpleKeys.count - 1].possible = false + simpleKeyAllowed = true + let startMark = reader.mark + reader.skip() + indentEngine.enqueue(Token(type: .blockEntry, startMark: startMark, endMark: reader.mark)) + } + + /// Port of `yaml_parser_fetch_key`. + private mutating func fetchKey() throws { + if tabbedSeparation { + throw tabIndentationError() + } + if flowLevel == 0 { + indentEngine.rollIndent(column: reader.column, number: -1, type: .blockMappingStart, mark: reader.mark) + } + simpleKeys[simpleKeys.count - 1].possible = false + simpleKeyAllowed = flowLevel == 0 + let startMark = reader.mark + reader.skip() + indentEngine.enqueue(Token(type: .key, startMark: startMark, endMark: reader.mark)) + } + + /// Port of `yaml_parser_fetch_value`, including the simple-key splice: a + /// possible simple key inserts its `KEY` token at the recorded position and + /// rolls the block mapping indent to the key's column. + private mutating func fetchValue() throws { + let top = simpleKeys.count - 1 + // A pending simple key means this `:` closes an inline implicit key (key + // and `:` on one line). An explicit `?` key's `:` has no pending simple key + // (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 `:` + // 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 ':'", + mark: simpleKeys[top].mark, + ) + } + if simpleKeys[top].possible { + if simpleKeys[top].tabbed { + throw tabIndentationError() + } + let key = simpleKeys[top] + indentEngine.insert(Token(type: .key, startMark: key.mark, endMark: key.mark), atTokenNumber: key.tokenNumber) + indentEngine.rollIndent(column: key.mark.column, number: key.tokenNumber, type: .blockMappingStart, mark: key.mark) + simpleKeys[top].possible = false + simpleKeyAllowed = false + } else { + if flowLevel == 0 { + indentEngine.rollIndent(column: reader.column, number: -1, type: .blockMappingStart, mark: reader.mark) + } + simpleKeyAllowed = flowLevel == 0 + } + let startMark = reader.mark + reader.skip() + indentEngine.enqueue(Token(type: .value, startMark: startMark, endMark: reader.mark)) + } + + /// Port of `yaml_parser_fetch_plain_scalar`. + private mutating func fetchPlainScalar() throws { + mark = reader.mark + try saveSimpleKey() + simpleKeyAllowed = false + let token = try scanPlainScalar() + indentEngine.enqueue(token) + } + + private func isDocumentMarker(_ character: Unicode.Scalar) -> Bool { + reader.peek(0) == character + && reader.peek(1) == character + && reader.peek(2) == character + && Classify.isBlankZ(reader.peek(3)) + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.FlowScalar.swift b/Sources/Parsing/LibYAML.Scanner.FlowScalar.swift new file mode 100644 index 0000000..d4f6f04 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.FlowScalar.swift @@ -0,0 +1,225 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + + /// The folding state carried through `scan_flow_scalar`, the same shape as the + /// plain-scalar state. + private struct FlowState { + var string = "" + var leadingBreak = "" + var trailingBreaks = "" + var whitespaces = "" + var leadingBlanks = false + } + + /// Decoded single-character escapes for double-quoted scalars (libyaml's escape + /// switch). libyaml emits UTF-8 bytes; here each maps to its Unicode scalar. + private static let doubleQuotedEscapes: [Unicode.Scalar: Unicode.Scalar] = [ + "0": "\u{0}", "a": "\u{07}", "b": "\u{08}", "t": "\u{09}", "\t": "\u{09}", + "n": "\u{0A}", "v": "\u{0B}", "f": "\u{0C}", "r": "\u{0D}", "e": "\u{1B}", + " ": "\u{20}", "\"": "\"", "/": "/", "\\": "\\", + "N": "\u{85}", "_": "\u{A0}", "L": "\u{2028}", "P": "\u{2029}", + ] + + /// Port of `yaml_parser_scan_flow_scalar`. Scans a single- or double-quoted + /// scalar, folding line breaks like a plain scalar and, for double quotes, + /// decoding escape sequences. + mutating func scanFlowScalar(single: Bool) throws -> PureYAML.Parsing.LibYAML.Token { + let startMark = reader.mark + reader.skip() + var state = FlowState() + let quote: Unicode.Scalar = single ? "'" : "\"" + let indent = indentEngine.indent + 1 + // A continuation indented below `indent` is an error, but it is recorded + // and only raised once the quote is known to close; an unterminated quote + // reaches end of input first and reports that instead. + var indentError: PureYAML.Parsing.LibYAML.ScannerError? + while true { + if reader.column == 0, documentMarkerAhead() { + throw flowError("found unexpected document indicator", startMark) + } + if reader.peek() == nil { + throw flowError("found unexpected end of stream", startMark) + } + try consumeFlowContent(single: single, &state, startMark: startMark) + if reader.peek() == quote { + break + } + consumeFlowBreaks(&state, indent: indent, quote: quote, startMark: startMark, error: &indentError) + foldFlow(&state) + } + reader.skip() + if let indentError { + throw indentError + } + return PureYAML.Parsing.LibYAML.Token( + type: .scalar(value: state.string, style: single ? .singleQuoted : .doubleQuoted), + startMark: startMark, + endMark: reader.mark, + ) + } + + /// Consume the run of non-blank characters, decoding escapes and stopping at + /// the closing quote or an escaped line break. + private mutating func consumeFlowContent(single: Bool, _ state: inout FlowState, startMark: PureYAML.Parsing.Mark) throws { + state.leadingBlanks = false + let quote: Unicode.Scalar = single ? "'" : "\"" + while let character = reader.peek(), !Classify.isBlankZ(character) { + if single, character == "'", reader.peek(1) == "'" { + state.string.unicodeScalars.append("'") + reader.skip() + reader.skip() + } else if character == quote { + return + } else if !single, character == "\\", Classify.isBreak(reader.peek(1)) { + reader.skip() + reader.skipLine() + state.leadingBlanks = true + return + } else if !single, character == "\\" { + try appendEscape(&state, startMark: startMark) + } else { + state.string.unicodeScalars.append(character) + reader.skip() + } + } + } + + /// Decode a double-quoted escape sequence (`\` already at the reader). + private mutating func appendEscape(_ state: inout FlowState, startMark: PureYAML.Parsing.Mark) throws { + let escape = reader.peek(1) + if let escape, let decoded = Self.doubleQuotedEscapes[escape] { + state.string.unicodeScalars.append(decoded) + reader.skip() + reader.skip() + return + } + let codeLength = try hexEscapeLength(escape, startMark: startMark) + reader.skip() + reader.skip() + var value = try readHexEscape(count: codeLength, startMark: startMark) + if codeLength == 4 { + value = try combineSurrogateIfNeeded(high: value, startMark: startMark) + } + guard let scalar = Unicode.Scalar(value) else { + throw flowError("found invalid Unicode character escape code", startMark) + } + state.string.unicodeScalars.append(scalar) + } + + /// The hex digit count for `\x` (2), `\u` (4), and `\U` (8) escapes. + private func hexEscapeLength(_ escape: Unicode.Scalar?, startMark: PureYAML.Parsing.Mark) throws -> Int { + switch escape { + case "x": 2 + case "u": 4 + case "U": 8 + default: throw flowError("found unknown escape character", startMark) + } + } + + /// Read and consume `count` hexadecimal digits, returning their value. + private mutating func readHexEscape(count: Int, startMark: PureYAML.Parsing.Mark) throws -> UInt32 { + var value: UInt32 = 0 + for _ in 0 ..< count { + guard let digit = reader.peek(), Classify.isHex(digit) else { + throw flowError("did not find expected hexdecimal number", startMark) + } + value = (value << 4) + hexValue(digit) + reader.skip() + } + return value + } + + /// Combine a UTF-16 surrogate pair (a high surrogate `\u` escape immediately + /// followed by a low surrogate `\u` escape) into a single astral code point, + /// for JSON compatibility. A lone high surrogate is left for the scalar check. + private mutating func combineSurrogateIfNeeded(high: UInt32, startMark: PureYAML.Parsing.Mark) throws -> UInt32 { + guard (0xD800 ... 0xDBFF).contains(high), reader.peek() == "\\", reader.peek(1) == "u" else { + return high + } + reader.skip() + reader.skip() + let low = try readHexEscape(count: 4, startMark: startMark) + guard (0xDC00 ... 0xDFFF).contains(low) else { + throw flowError("found invalid Unicode character escape code", startMark) + } + return 0x10000 + ((high - 0xD800) << 10) + (low - 0xDC00) + } + + /// Consume blanks and line breaks between content, recording pending + /// whitespace and folded breaks. + private mutating func consumeFlowBreaks( + _ state: inout FlowState, + indent: Int, + quote: Unicode.Scalar, + startMark: PureYAML.Parsing.Mark, + error: inout PureYAML.Parsing.LibYAML.ScannerError?, + ) { + while Classify.isBlank(reader.peek()) || Classify.isBreak(reader.peek()) { + if Classify.isBlank(reader.peek()) { + if error == nil, state.leadingBlanks, reader.column < indent, Classify.isTab(reader.peek()), !blankLineAhead() { + error = flowError("found a tab character that violates indentation", startMark) + } + if !state.leadingBlanks, let blank = reader.peek() { + state.whitespaces.unicodeScalars.append(blank) + } + reader.skip() + } else if !state.leadingBlanks { + state.whitespaces = "" + reader.skipLine() + state.leadingBreak = "\n" + state.leadingBlanks = true + } else { + reader.skipLine() + state.trailingBreaks += "\n" + } + } + // The continuation content must be indented at least `indent`; a less + // indented (non-closing, non-empty) line is malformed. + if error == nil, state.leadingBlanks, let next = reader.peek(), next != quote, !Classify.isBreakZ(next), reader.column < indent { + error = flowError("found wrong indentation in a multi-line quoted scalar", startMark) + } + } + + /// Fold the pending breaks or whitespace into the value. + private func foldFlow(_ state: inout FlowState) { + guard state.leadingBlanks else { + state.string += state.whitespaces + state.whitespaces = "" + return + } + if state.leadingBreak.first == "\n" { + if state.trailingBreaks.isEmpty { + state.string += " " + } else { + state.string += state.trailingBreaks + state.trailingBreaks = "" + } + state.leadingBreak = "" + } else { + state.string += state.leadingBreak + state.string += state.trailingBreaks + state.leadingBreak = "" + state.trailingBreaks = "" + } + } + + private func hexValue(_ scalar: Unicode.Scalar) -> UInt32 { + switch scalar { + case "0" ... "9": scalar.value - Unicode.Scalar("0").value + case "A" ... "F": scalar.value - Unicode.Scalar("A").value + 10 + default: scalar.value - Unicode.Scalar("a").value + 10 + } + } + + private func flowError(_ problem: String, _ mark: PureYAML.Parsing.Mark) -> PureYAML.Parsing.LibYAML.ScannerError { + PureYAML.Parsing.LibYAML.ScannerError(context: "while scanning a quoted scalar", problem: problem, mark: mark) + } + + private func documentMarkerAhead() -> Bool { + let first = reader.peek() + guard first == "-" || first == "." else { + return false + } + return reader.peek(1) == first && reader.peek(2) == first && Classify.isBlankZ(reader.peek(3)) + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.Guards.swift b/Sources/Parsing/LibYAML.Scanner.Guards.swift new file mode 100644 index 0000000..6108499 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.Guards.swift @@ -0,0 +1,59 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias ScannerError = PureYAML.Parsing.LibYAML.ScannerError + + /// Reject a flow-collection continuation line that is not indented past the + /// enclosing block context. YAML requires `s-flow-line-prefix` to be more + /// indented than the parent block; libyaml does not enforce it, so multi-line + /// flow content in column 0 (`[a,\nb]` under a key) wrongly parses. + mutating func checkFlowContinuationIndent() throws { + guard flowLevel > 0, crossedLineBreak, let next = reader.peek() else { + return + } + // A closing `]`/`}` (or a `,` separator) may sit at any indentation; only + // flow CONTENT must be indented past the parent block. + if next == "]" || next == "}" || next == "," { + return + } + // A tab in the leading whitespace is never valid indentation, even where + // spaces of the same width would be (the tab inflates the column). + if reader.column <= indentEngine.indent || flowLeadingTab { + throw ScannerError( + context: "while parsing a flow node", + problem: "found insufficiently indented line in a flow collection", + mark: reader.mark, + ) + } + } + + /// Whether the last emitted token bars a block sequence from opening on the + /// same line: a mapping value indicator or a node property (anchor/tag). After + /// another block entry a compact sequence is allowed, so that is not barred. + func lastTokenForbidsInlineSequence() -> Bool { + switch indentEngine.tokens.last?.type { + case .anchor, .tag: + true + case .value: + lastValueWasInline + default: + false + } + } + + /// The error raised when a tab is used where indentation is required (before a + /// block indicator or an implicit mapping key). A tab is valid separation but + /// never indentation. + func tabIndentationError() -> PureYAML.Parsing.LibYAML.ScannerError { + ScannerError( + context: "while scanning for the next token", + problem: "found a tab character where an indentation space is expected", + mark: reader.mark, + ) + } + + /// Whether this flow level's pending simple key is a JSON (quoted) node, which + /// lets an adjacent `:` open its value without a separating space. + var flowKeyIsJSON: Bool { + let key = simpleKeys[simpleKeys.count - 1] + return key.possible && key.isJSON + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.PlainScalar.swift b/Sources/Parsing/LibYAML.Scanner.PlainScalar.swift new file mode 100644 index 0000000..900e14c --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.PlainScalar.swift @@ -0,0 +1,142 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + + /// The folding state carried through `scan_plain_scalar`: the accumulated + /// value plus the pending leading break, trailing breaks, and whitespace that + /// are folded in before the next content character. + private struct PlainState { + var string = "" + var leadingBreak = "" + var trailingBreaks = "" + var whitespaces = "" + var leadingBlanks = false + var endMark: PureYAML.Parsing.Mark + } + + /// Port of `yaml_parser_scan_plain_scalar`. Consumes a plain scalar, folding + /// line breaks: a single break between non-empty lines becomes a space, blank + /// lines become literal newlines, and leading/trailing whitespace on folded + /// lines is dropped. Ends at a `: ` value indicator, a comment, a less-indented + /// line (block context), a flow indicator (flow context), or a document marker. + mutating func scanPlainScalar() throws -> PureYAML.Parsing.LibYAML.Token { + let indent = indentEngine.indent + 1 + let startMark = reader.mark + var state = PlainState(endMark: reader.mark) + + while true { + if reader.column == 0, documentMarkerAhead() { + break + } + if reader.peek() == "#" { + break + } + try consumePlainContent(&state, startMark: startMark) + guard Classify.isBlank(reader.peek()) || Classify.isBreak(reader.peek()) else { + break + } + try consumePlainBreaks(&state, indent: indent, startMark: startMark) + if flowLevel == 0, reader.column < indent { + break + } + } + + if state.leadingBlanks { + simpleKeyAllowed = true + } + return PureYAML.Parsing.LibYAML.Token( + type: .scalar(value: state.string, style: .plain), + startMark: startMark, + endMark: state.endMark, + ) + } + + /// Consume the run of non-blank characters, folding any pending breaks or + /// whitespace ahead of each one. + private mutating func consumePlainContent(_ state: inout PlainState, startMark _: PureYAML.Parsing.Mark) throws { + while let character = reader.peek(), !Classify.isBlankZ(character) { + if character == ":", Classify.isBlankZ(reader.peek(1)) { + break + } + if flowLevel > 0, character == ":", Classify.isFlowIndicator(reader.peek(1)) { + // A `:` before a flow indicator ends the key; the value is empty. + // libyaml rejects this as an unexpected ':', but it is a valid + // value indicator in flow context. + break + } + if flowLevel > 0, Classify.isFlowIndicator(character) { + break + } + foldPending(&state) + state.string.unicodeScalars.append(character) + reader.skip() + state.endMark = reader.mark + } + } + + /// Fold the pending leading break, trailing breaks, and whitespace into the + /// accumulated value (the join logic from libyaml's inner loop). + private func foldPending(_ state: inout PlainState) { + guard state.leadingBlanks || !state.whitespaces.isEmpty else { + return + } + guard state.leadingBlanks else { + state.string += state.whitespaces + state.whitespaces = "" + return + } + if state.leadingBreak.first == "\n" { + if state.trailingBreaks.isEmpty { + state.string += " " + } else { + state.string += state.trailingBreaks + state.trailingBreaks = "" + } + state.leadingBreak = "" + } else { + state.string += state.leadingBreak + state.string += state.trailingBreaks + state.leadingBreak = "" + state.trailingBreaks = "" + } + state.leadingBlanks = false + } + + /// Consume the run of blanks and line breaks between content, recording them as + /// pending whitespace or folded breaks. + private mutating func consumePlainBreaks(_ state: inout PlainState, indent: Int, startMark: PureYAML.Parsing.Mark) throws { + while Classify.isBlank(reader.peek()) || Classify.isBreak(reader.peek()) { + if Classify.isBlank(reader.peek()) { + if state.leadingBlanks, reader.column < indent, Classify.isTab(reader.peek()), !blankLineAhead() { + // A tab below the indentation is illegal only when it indents + // real content; on an otherwise-blank line it is just a blank + // line the scalar folds over. libyaml rejects it either way. + throw scannerError("found a tab character that violates indentation", at: startMark) + } + if !state.leadingBlanks, let blank = reader.peek() { + state.whitespaces.unicodeScalars.append(blank) + } + reader.skip() + } else if !state.leadingBlanks { + state.whitespaces = "" + reader.skipLine() + state.leadingBreak = "\n" + state.leadingBlanks = true + } else { + reader.skipLine() + state.trailingBreaks += "\n" + } + } + } + + private func scannerError(_ problem: String, at mark: PureYAML.Parsing.Mark) -> PureYAML.Parsing.LibYAML.ScannerError { + PureYAML.Parsing.LibYAML.ScannerError(context: "while scanning a plain scalar", problem: problem, mark: mark) + } + + private func documentMarkerAhead() -> Bool { + let first = reader.peek() + guard first == "-" || first == "." else { + return false + } + return reader.peek(1) == first && reader.peek(2) == first && Classify.isBlankZ(reader.peek(3)) + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.SkipToToken.swift b/Sources/Parsing/LibYAML.Scanner.SkipToToken.swift new file mode 100644 index 0000000..a210daa --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.SkipToToken.swift @@ -0,0 +1,88 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + private typealias ScannerError = PureYAML.Parsing.LibYAML.ScannerError + + /// Port of `yaml_parser_scan_to_next_token`: skip a leading BOM, spaces and + /// tabs, a comment, and a single line break, which re-allows a simple key in + /// the block context. A tab is valid in-line separation, so it is skipped + /// here; `tabbedSeparation` records when one preceded the token so a block + /// indicator or implicit key (where the tab would be indentation) can reject. + mutating func scanToNextToken() throws { + crossedLineBreak = false + flowLeadingTab = false + while true { + tabbedSeparation = false + if reader.column == 0, reader.peek() == "\u{FEFF}" { + reader.skip() + } + while reader.peek() == " " || Classify.isTab(reader.peek()) { + if Classify.isTab(reader.peek()) { + noteLeadingTab() + } + reader.skip() + } + // YAML 1.2: a line containing only whitespace is blank even when that + // whitespace includes tabs. libyaml leaves a leading tab in place and + // later rejects it; instead consume the trailing blanks so the line + // break below is reached and the blank line is skipped. + if blankLineAhead() { + while reader.peek() == " " || Classify.isTab(reader.peek()) { + reader.skip() + } + } + if reader.peek() == "#" { + try consumeComment() + } + if Classify.isBreak(reader.peek()) { + reader.skipLine() + crossedLineBreak = true + if flowLevel == 0 { + simpleKeyAllowed = true + } + } else { + break + } + } + } + + /// Record what a tab in the leading whitespace implies. In block context with a + /// simple key allowed it is potential indentation before an indicator. In flow + /// context, below the continuation indent on a non-blank line it is indentation + /// abuse (a tab is never indentation); at or above the indent it is separation. + private mutating func noteLeadingTab() { + if flowLevel == 0, simpleKeyAllowed { + tabbedSeparation = true + } + if flowLevel > 0, crossedLineBreak, reader.column < indentEngine.indent + 1, !blankLineAhead() { + flowLeadingTab = true + } + } + + /// Consume a comment to the end of the line. A comment must be preceded by + /// whitespace or start the line; a `#` adjacent to the previous token (e.g. + /// `"x"#`, `]#`, `,#`) is not a comment. The plain-scalar scanner consumes its + /// own trailing blanks, so the character just before the `#` is the reliable + /// signal. libyaml accepts the adjacent form. + private mutating func consumeComment() throws { + if reader.column > 0, let previous = reader.peek(-1), !Classify.isBlank(previous) { + throw ScannerError( + context: "while scanning for the next token", + problem: "found a comment without a preceding space", + mark: reader.mark, + ) + } + while !Classify.isBreakZ(reader.peek()) { + reader.skip() + } + } + + /// Whether the rest of the current line, from the current position, is only + /// spaces and tabs up to a line break or end of stream (a blank line). + func blankLineAhead() -> Bool { + var offset = 0 + while let character = reader.peek(offset), character == " " || Classify.isTab(character) { + offset += 1 + } + return Classify.isBreakZ(reader.peek(offset)) + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.Tag.swift b/Sources/Parsing/LibYAML.Scanner.Tag.swift new file mode 100644 index 0000000..a3fd681 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.Tag.swift @@ -0,0 +1,155 @@ +extension PureYAML.Parsing.LibYAML.Scanner { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + + /// Port of `yaml_parser_scan_tag`. Scans a tag in verbatim `!`, shorthand + /// `!handle!suffix`, or `!suffix` form, producing the handle and suffix; the + /// parser resolves them against the tag directives. + mutating func scanTag() throws -> PureYAML.Parsing.LibYAML.Token { + let startMark = reader.mark + var handle = "" + var suffix = "" + if reader.peek(1) == "<" { + reader.skip() + reader.skip() + suffix = try scanTagURI(uriChar: true, directive: false, head: "", startMark: startMark) + guard reader.peek() == ">" else { + throw tagError("did not find the expected '>'", startMark) + } + reader.skip() + } else { + handle = try scanTagHandle(directive: false, startMark: startMark) + if handle.first == "!", handle.count > 1, handle.last == "!" { + suffix = try scanTagURI(uriChar: false, directive: false, head: "", startMark: startMark) + } else { + suffix = try scanTagURI(uriChar: false, directive: false, head: handle, startMark: startMark) + handle = "!" + if suffix.isEmpty { + swap(&handle, &suffix) + } + } + } + guard Classify.isBlankZ(reader.peek()) || (flowLevel > 0 && reader.peek() == ",") else { + throw tagError("did not find expected whitespace or line break", startMark) + } + return PureYAML.Parsing.LibYAML.Token(type: .tag(handle: handle, suffix: suffix), startMark: startMark, endMark: reader.mark) + } + + /// Port of `yaml_parser_scan_tag_handle`. A handle is `!`, optionally followed + /// by alphanumeric characters and a closing `!`. + mutating func scanTagHandle(directive: Bool, startMark: PureYAML.Parsing.Mark) throws -> String { + guard reader.peek() == "!" else { + throw tagError("did not find expected '!'", startMark) + } + var handle = "!" + reader.skip() + while let character = reader.peek(), Classify.isAlpha(character) { + handle.unicodeScalars.append(character) + reader.skip() + } + if reader.peek() == "!" { + handle.unicodeScalars.append("!") + reader.skip() + } else if directive, handle != "!" { + throw tagError("did not find expected '!'", startMark) + } + return handle + } + + /// Port of `yaml_parser_scan_tag_uri`. Consumes the URI character set (plus the + /// flow indicators inside a verbatim tag), decoding `%`-escapes. + mutating func scanTagURI(uriChar: Bool, directive: Bool, head: String, startMark: PureYAML.Parsing.Mark) throws -> String { + var string = head.count > 1 ? String(head.dropFirst()) : "" + var length = head.isEmpty ? 0 : head.count + while let character = reader.peek(), isURICharacter(character, uriChar: uriChar) { + if character == "%" { + try scanURIEscapes(directive: directive, startMark: startMark, into: &string) + } else { + string.unicodeScalars.append(character) + reader.skip() + } + length += 1 + } + guard length > 0 else { + throw tagError("did not find expected tag URI", startMark) + } + return string + } + + /// Port of `yaml_parser_scan_uri_escapes`. Decodes one UTF-8 character from a + /// run of `%XX` octets. + private mutating func scanURIEscapes(directive _: Bool, startMark: PureYAML.Parsing.Mark, into string: inout String) throws { + var bytes: [UInt8] = [] + var width = 0 + repeat { + guard reader.peek() == "%", let high = reader.peek(1), Classify.isHex(high), let low = reader.peek(2), Classify.isHex(low) else { + throw tagError("did not find URI escaped octet", startMark) + } + let octet = UInt8((hexDigit(high) << 4) + hexDigit(low)) + if width == 0 { + width = utf8Width(of: octet) + guard width > 0 else { + throw tagError("found an incorrect leading UTF-8 octet", startMark) + } + } else if octet & 0xC0 != 0x80 { + throw tagError("found an incorrect trailing UTF-8 octet", startMark) + } + bytes.append(octet) + reader.skip() + reader.skip() + reader.skip() + width -= 1 + } while width > 0 + guard let scalar = Unicode.Scalar(decodeUTF8(bytes)) else { + throw tagError("found invalid UTF-8 in a URI escape", startMark) + } + string.unicodeScalars.append(scalar) + } + + /// Assemble a code point from the validated 1-to-4 UTF-8 octets of one escape. + private func decodeUTF8(_ bytes: [UInt8]) -> UInt32 { + switch bytes.count { + case 1: + UInt32(bytes[0]) + case 2: + (UInt32(bytes[0] & 0x1F) << 6) | UInt32(bytes[1] & 0x3F) + case 3: + (UInt32(bytes[0] & 0x0F) << 12) | (UInt32(bytes[1] & 0x3F) << 6) | UInt32(bytes[2] & 0x3F) + default: + (UInt32(bytes[0] & 0x07) << 18) | (UInt32(bytes[1] & 0x3F) << 12) | (UInt32(bytes[2] & 0x3F) << 6) | UInt32(bytes[3] & 0x3F) + } + } + + private func utf8Width(of octet: UInt8) -> Int { + if octet & 0x80 == 0x00 { return 1 } + if octet & 0xE0 == 0xC0 { return 2 } + if octet & 0xF0 == 0xE0 { return 3 } + if octet & 0xF8 == 0xF0 { return 4 } + return 0 + } + + private func isURICharacter(_ scalar: Unicode.Scalar, uriChar: Bool) -> Bool { + if Classify.isAlpha(scalar) { + return true + } + switch scalar { + case ";", "/", "?", ":", "@", "&", "=", "+", "$", ".", "%", "!", "~", "*", "'", "(", ")": + return true + case ",", "[", "]": + return uriChar + default: + return false + } + } + + private func hexDigit(_ scalar: Unicode.Scalar) -> Int { + switch scalar { + case "0" ... "9": Int(scalar.value - Unicode.Scalar("0").value) + case "A" ... "F": Int(scalar.value - Unicode.Scalar("A").value) + 10 + default: Int(scalar.value - Unicode.Scalar("a").value) + 10 + } + } + + private func tagError(_ problem: String, _ mark: PureYAML.Parsing.Mark) -> PureYAML.Parsing.LibYAML.ScannerError { + PureYAML.Parsing.LibYAML.ScannerError(context: "while scanning a tag", problem: problem, mark: mark) + } +} diff --git a/Sources/Parsing/LibYAML.Scanner.swift b/Sources/Parsing/LibYAML.Scanner.swift new file mode 100644 index 0000000..b0e2676 --- /dev/null +++ b/Sources/Parsing/LibYAML.Scanner.swift @@ -0,0 +1,139 @@ +extension PureYAML.Parsing.LibYAML { + /// Aggregate scanner state, mirroring the fields of `yaml_parser_t` that the + /// ported functions read and write. It is built up as the port proceeds; + /// currently it holds the indentation engine and the simple-key mechanism. + /// Column values follow libyaml's 0-based convention internally; conversion to + /// the package's 1-based `Mark` happens at token emission during integration. + struct Scanner { + /// The input buffer and position (`parser->buffer` / `parser->mark`). + var reader: Reader + /// The indentation stack and `roll_indent` / `unroll_indent` (also the + /// owner of `flow_level` and the token queue). + var indentEngine = IndentEngine() + /// `parser->simple_keys`. Always holds at least the block-context level. + var simpleKeys: [SimpleKey] = [.empty] + /// `parser->simple_key_allowed`. True at stream start. + var simpleKeyAllowed = true + /// Whether a tab appeared in the indentation before the pending token. A + /// tab is valid in-line separation but never indentation, so a block + /// indicator or implicit mapping key reached through one is an error. + var tabbedSeparation = false + /// Whether reaching the pending token crossed at least one line break. In + /// flow context a continuation line must be indented past the parent block, + /// so a token on a new line at or below that indent is an error. + var crossedLineBreak = false + /// Whether a tab appeared in the leading whitespace of a flow continuation + /// line. A tab is never indentation, so flow content reached through one is + /// an error even though the tab inflates the column. + var flowLeadingTab = false + /// Whether the most recent `:` value indicator sat on the same line as its + /// key (an inline implicit-key value). Such a value may not open a block + /// sequence on that line (`key: - a`), whereas an explicit key whose `:` is + /// on a later line may (`? k`\n`: - a`). + var lastValueWasInline = false + /// For each open flow level, whether it is a sequence (`[`) rather than a + /// mapping (`{`). A flow-sequence single-pair implicit key is single-line + /// (`c-s-implicit-json-key`), so its `:` may not cross a line break, unlike + /// a flow-mapping adjacent value (`{ "a"`\n`: b }` is allowed). + var flowIsSequence: [Bool] = [] + /// `parser->mark`, kept in sync with the reader at each fetch step. + var mark: PureYAML.Parsing.Mark = .start + /// `parser->stream_start_produced`. + var streamStartProduced = false + /// `parser->stream_end_produced`. + var streamEndProduced = false + + init(_ input: String = "") { + reader = Reader(input) + } + + /// `parser->flow_level`, kept on the indent engine. + var flowLevel: Int { + indentEngine.flowLevel + } + + /// Port of `yaml_parser_stale_simple_keys`. A potential simple key is + /// invalid once it is on an earlier line or more than 1024 characters back + /// (a simple key is single-line and bounded); a required one going stale is + /// an error. + mutating func staleSimpleKeys() throws { + for index in simpleKeys.indices { + let key = simpleKeys[index] + guard key.possible else { + continue + } + // A block-context key (index 0) is single-line. A flow-context key + // (index >= 1) may be separated from its ':' by line breaks under + // YAML 1.2, so a new line alone does not invalidate it; both remain + // bounded to 1024 characters. libyaml invalidates every key on a new + // line, which wrongly rejects multi-line flow keys. + let tooFarBack = key.mark.index + 1024 < mark.index + let stale = index == 0 ? (key.mark.line < mark.line || tooFarBack) : tooFarBack + guard stale else { + continue + } + if key.required { + throw ScannerError( + context: "while scanning a simple key", + problem: "could not find expected ':'", + mark: key.mark, + ) + } + simpleKeys[index].possible = false + } + } + + /// Port of `yaml_parser_save_simple_key`. Record the current position as a + /// potential simple key for this flow level when one is allowed. A key is + /// required (a `:` must follow) when it sits exactly at the block indent. + mutating func saveSimpleKey() throws { + let required = flowLevel == 0 && indentEngine.indent == mark.column + guard simpleKeyAllowed else { + return + } + let key = SimpleKey( + possible: true, + required: required, + tokenNumber: indentEngine.tokensParsed + indentEngine.tokens.count, + mark: mark, + tabbed: tabbedSeparation, + ) + try removeSimpleKey() + simpleKeys[simpleKeys.count - 1] = key + } + + /// Port of `yaml_parser_remove_simple_key`. Drop the potential key at the + /// current flow level; removing a required key is an error. + mutating func removeSimpleKey() throws { + let top = simpleKeys.count - 1 + if simpleKeys[top].possible, simpleKeys[top].required { + throw ScannerError( + context: "while scanning a simple key", + problem: "could not find expected ':'", + mark: simpleKeys[top].mark, + ) + } + simpleKeys[top].possible = false + } + + /// Port of `yaml_parser_increase_flow_level`. Push an empty simple key for + /// the new flow level, recording whether the level is a sequence. + mutating func increaseFlowLevel(isSequence: Bool) { + simpleKeys.append(.empty) + flowIsSequence.append(isSequence) + indentEngine.flowLevel += 1 + } + + /// Port of `yaml_parser_decrease_flow_level`. Pop the flow level's simple + /// key. + mutating func decreaseFlowLevel() { + if indentEngine.flowLevel > 0 { + indentEngine.flowLevel -= 1 + simpleKeys.removeLast() + if !flowIsSequence.isEmpty { + flowIsSequence.removeLast() + } + } + } + } +} diff --git a/Sources/Parsing/LibYAML.ScannerError.swift b/Sources/Parsing/LibYAML.ScannerError.swift new file mode 100644 index 0000000..49f1887 --- /dev/null +++ b/Sources/Parsing/LibYAML.ScannerError.swift @@ -0,0 +1,10 @@ +extension PureYAML.Parsing.LibYAML { + /// A scanning error, mirroring libyaml's `yaml_parser_set_scanner_error` + /// (`context` plus `problem` at a mark). It is mapped to the package's public + /// `ParseError` when the port is integrated. + struct ScannerError: Swift.Error, Equatable { + var context: String + var problem: String + var mark: PureYAML.Parsing.Mark + } +} diff --git a/Sources/Parsing/LibYAML.SimpleKey.swift b/Sources/Parsing/LibYAML.SimpleKey.swift new file mode 100644 index 0000000..ac438e6 --- /dev/null +++ b/Sources/Parsing/LibYAML.SimpleKey.swift @@ -0,0 +1,28 @@ +extension PureYAML.Parsing.LibYAML { + /// Port of `yaml_simple_key_t`. A potential implicit ("simple") mapping key: + /// a node that may turn out to be a key once a `:` is seen on the same line. + /// `tokenNumber` records where its `KEY` token must be spliced into the queue. + struct SimpleKey: Equatable { + /// Whether a simple key is still possible at this flow level. + var possible: Bool + /// Whether a `:` is required (a key sitting exactly at the block indent). + var required: Bool + /// The absolute token number where the `KEY` token is inserted. + var tokenNumber: Int + /// The position the potential key started at. + var mark: PureYAML.Parsing.Mark + /// Whether this key is a JSON-style node (a quoted flow scalar). A `:` + /// adjacent to such a key is a value indicator even without a following + /// space, per the YAML flow "adjacent value" rule. + var isJSON = false + /// Whether a tab preceded this key in its indentation. A tab may be + /// separation but never indentation, so promoting such a key to a block + /// mapping key (a `:` follows) is an error. + var tabbed = false + + /// The empty entry pushed for a new flow level (`{ 0, 0, 0, {0,0,0} }`). + static var empty: Self { + Self(possible: false, required: false, tokenNumber: 0, mark: .start) + } + } +} diff --git a/Sources/Parsing/LibYAML.Token.swift b/Sources/Parsing/LibYAML.Token.swift new file mode 100644 index 0000000..fe6078a --- /dev/null +++ b/Sources/Parsing/LibYAML.Token.swift @@ -0,0 +1,10 @@ +extension PureYAML.Parsing.LibYAML { + /// A scanner token, mirroring `yaml_token_t`: a kind plus its start and end + /// marks. Token-specific payloads (scalar value, anchor name, tag) are added + /// as their fetchers are ported. + struct Token: Equatable { + var type: TokenType + var startMark: PureYAML.Parsing.Mark + var endMark: PureYAML.Parsing.Mark + } +} diff --git a/Sources/Parsing/LibYAML.TokenType.swift b/Sources/Parsing/LibYAML.TokenType.swift new file mode 100644 index 0000000..a750630 --- /dev/null +++ b/Sources/Parsing/LibYAML.TokenType.swift @@ -0,0 +1,29 @@ +extension PureYAML.Parsing.LibYAML { + /// A scanner token kind, mirroring `yaml_token_type_t`. The flow-collection, + /// anchor, tag, alias, and directive kinds are added as their fetchers are + /// ported; the block + plain-scalar core is present. + enum TokenType: Equatable { + case streamStart + case streamEnd + case documentStart + case documentEnd + case blockSequenceStart + case blockMappingStart + case blockEnd + case blockEntry + case flowSequenceStart + case flowMappingStart + case flowSequenceEnd + case flowMappingEnd + case flowEntry + case key + case value + case versionDirective(major: Int, minor: Int) + case tagDirective(handle: String, prefix: String) + case reservedDirective + case anchor(name: String) + case alias(name: String) + case tag(handle: String, suffix: String) + case scalar(value: String, style: PureYAML.Parsing.ScalarStyle) + } +} diff --git a/Sources/Parsing/LibYAML.swift b/Sources/Parsing/LibYAML.swift new file mode 100644 index 0000000..162a852 --- /dev/null +++ b/Sources/Parsing/LibYAML.swift @@ -0,0 +1,10 @@ +extension PureYAML.Parsing { + /// Faithful Swift port of libyaml's scanner (`CYaml/src/scanner.c`). It is + /// built as a parallel implementation, verified token-for-token against + /// libyaml through the differential harness, to replace the hand-rolled + /// approximation whose indentation and simple-key handling the official test + /// suite surfaced as incorrect. The port proceeds function by function; each + /// piece mirrors its C counterpart so correctness is by construction rather + /// than re-derived. Members live under this namespace in their own files. + enum LibYAML {} +} diff --git a/Sources/Parsing/NodeProperties.swift b/Sources/Parsing/NodeProperties.swift deleted file mode 100644 index f53a175..0000000 --- a/Sources/Parsing/NodeProperties.swift +++ /dev/null @@ -1,17 +0,0 @@ -extension PureYAML.Parsing { - struct NodeProperties: Equatable { - var anchor: String? - var tag: String? - var mark: Mark? - - static var none: Self { - Self(anchor: nil, tag: nil, mark: nil) - } - - mutating func mergeUnset(from other: Self) { - anchor = anchor ?? other.anchor - tag = tag ?? other.tag - mark = mark ?? other.mark - } - } -} diff --git a/Sources/Parsing/NodeResult.swift b/Sources/Parsing/NodeResult.swift deleted file mode 100644 index 34333cc..0000000 --- a/Sources/Parsing/NodeResult.swift +++ /dev/null @@ -1,6 +0,0 @@ -extension PureYAML.Parsing { - struct NodeResult: Equatable { - var kind: NodeKind - var endMark: Mark - } -} diff --git a/Sources/Parsing/ParseError.LibYAML.swift b/Sources/Parsing/ParseError.LibYAML.swift new file mode 100644 index 0000000..24cb8c1 --- /dev/null +++ b/Sources/Parsing/ParseError.LibYAML.swift @@ -0,0 +1,39 @@ +extension PureYAML.Parsing.ParseError { + /// Translate a ported-scanner error into the package's diagnostic-aware error, + /// converting libyaml's 0-based mark to the 1-based convention and mapping the + /// well-known scanner failures to precise diagnostic codes. + init(translating error: PureYAML.Parsing.LibYAML.ScannerError) { + let line = error.mark.line + 1 + let column = error.mark.column + 1 + let context = error.context ?? "" + if error.problem.hasPrefix("found a tab") { + self = .tabIndentation(line: line) + } else if context == "while scanning a quoted scalar", error.problem.hasSuffix("end of stream") { + self = .unterminatedQuotedString(line: line) + } else if context.hasPrefix("while scanning a tag") || context.hasSuffix("TAG directive") { + self = .unterminatedTag(line: line) + } else { + self = .malformed(reason: Self.reason(context: error.context, problem: error.problem), line: line, column: column) + } + } + + /// Translate a ported-parser error into the package's diagnostic-aware error. + init(translating error: PureYAML.Parsing.LibYAML.ParserError) { + let line = error.mark.line + 1 + let column = error.mark.column + 1 + if error.problem == "found incompatible YAML document" { + self = .incompatibleYAMLDirective(line: line) + } else { + self = .malformed(reason: Self.reason(context: error.context, problem: error.problem), line: line, column: column) + } + } + + /// Join a libyaml context and problem into one readable reason, e.g. + /// "while parsing a flow sequence, did not find expected ',' or ']'". + private static func reason(context: String?, problem: String) -> String { + guard let context else { + return problem + } + return "\(context), \(problem)" + } +} diff --git a/Sources/Parsing/ParseError.swift b/Sources/Parsing/ParseError.swift index 547ad37..3f5e8c5 100644 --- a/Sources/Parsing/ParseError.swift +++ b/Sources/Parsing/ParseError.swift @@ -1,13 +1,17 @@ public extension PureYAML.Parsing { /// Parser error with source line information when available. enum ParseError: Swift.Error, Equatable, Sendable, CustomStringConvertible { + case emptyDocument + case tabIndentation(line: Int) case unexpectedIndentation(line: Int) case mixedCollectionStyles(line: Int) + case expectedMappingKey(line: Int) case expectedAnchorName(line: Int) case expectedAliasName(line: Int) case expectedNode(line: Int, column: Int) case expectedScalarKey(line: Int, column: Int) case incompatibleYAMLDirective(line: Int) + case directiveWithoutDocument(line: Int) case invalidTaggedScalar(tag: String, value: String, line: Int, column: Int) case invalidMergeValue(line: Int, column: Int) case unterminatedTag(line: Int) @@ -18,25 +22,20 @@ public extension PureYAML.Parsing { case unexpectedEvent(expected: String, actual: String, line: Int, column: Int) case unexpectedToken(expected: String, actual: String, line: Int, column: Int) case nestingTooDeep(line: Int, column: Int) - case commentNotPrecededByWhitespace(line: Int, column: Int) - case invalidEscape(sequence: String, line: Int) - case malformedDirective(name: String, line: Int) - case duplicateDirective(name: String, line: Int) - case directiveWithoutDocument(line: Int) - case contentAfterDocumentEnd(line: Int) - case blockSequenceAsInlineMappingValue(line: Int) - case multilineImplicitKey(line: Int) - case commentInMultilineScalar(line: Int) - case aliasWithProperties(line: Int, column: Int) - case inlineBlockSequenceAfterProperty(line: Int, column: Int) - case documentMarkerInScalar(line: Int) + case malformed(reason: String, line: Int, column: Int) public var description: String { switch self { + case .emptyDocument: + "document is empty" + case let .tabIndentation(line): + "tabs are not allowed for indentation at line \(line)" case let .unexpectedIndentation(line): "unexpected indentation at line \(line)" case let .mixedCollectionStyles(line): "mapping and sequence entries are mixed at line \(line)" + case let .expectedMappingKey(line): + "expected a mapping key at line \(line)" case let .expectedAnchorName(line): "expected an anchor name at line \(line)" case let .expectedAliasName(line): @@ -47,6 +46,8 @@ public extension PureYAML.Parsing { "expected a scalar mapping key at line \(line), column \(column)" case let .incompatibleYAMLDirective(line): "incompatible YAML directive at line \(line)" + case let .directiveWithoutDocument(line): + "directive is not followed by a document start at line \(line)" case let .invalidTaggedScalar(tag, value, line, column): "invalid scalar '\(value)' for tag '\(tag)' at line \(line), column \(column)" case let .invalidMergeValue(line, column): @@ -67,39 +68,23 @@ public extension PureYAML.Parsing { "expected \(expected) at line \(line), column \(column), found \(actual)" case let .nestingTooDeep(line, column): "nesting is too deep at line \(line), column \(column)" - case let .commentNotPrecededByWhitespace(line, column): - "a comment must be preceded by whitespace at line \(line), column \(column)" - case let .invalidEscape(sequence, line): - "invalid escape sequence '\(sequence)' at line \(line)" - case let .malformedDirective(name, line): - "malformed directive '\(name)' at line \(line)" - case let .duplicateDirective(name, line): - "duplicate directive '\(name)' at line \(line)" - case let .directiveWithoutDocument(line): - "a directive must be followed by a document at line \(line)" - case let .contentAfterDocumentEnd(line): - "no content may follow a document end marker at line \(line)" - case let .blockSequenceAsInlineMappingValue(line): - "a block sequence cannot start on the same line as a mapping value at line \(line)" - case let .multilineImplicitKey(line): - "an implicit mapping key must not span multiple lines at line \(line)" - case let .commentInMultilineScalar(line): - "a comment cannot interrupt a multi-line plain scalar at line \(line)" - case let .aliasWithProperties(line, column): - "an alias node cannot have an anchor or tag at line \(line), column \(column)" - case let .inlineBlockSequenceAfterProperty(line, column): - "a block sequence cannot start on the same line as its anchor or tag at line \(line), column \(column)" - case let .documentMarkerInScalar(line): - "a document marker cannot appear inside a multi-line scalar at line \(line)" + case let .malformed(reason, line, column): + "\(reason) at line \(line), column \(column)" } } public var diagnosticCode: String { switch self { + case .emptyDocument: + "emptyDocument" + case .tabIndentation: + "tabIndentation" case .unexpectedIndentation: "unexpectedIndentation" case .mixedCollectionStyles: "mixedCollectionStyles" + case .expectedMappingKey: + "expectedMappingKey" case .expectedAnchorName: "expectedAnchorName" case .expectedAliasName: @@ -110,6 +95,8 @@ public extension PureYAML.Parsing { "expectedScalarKey" case .incompatibleYAMLDirective: "incompatibleYAMLDirective" + case .directiveWithoutDocument: + "directiveWithoutDocument" case .invalidTaggedScalar: "invalidTaggedScalar" case .invalidMergeValue: @@ -130,53 +117,27 @@ public extension PureYAML.Parsing { "unexpectedToken" case .nestingTooDeep: "nestingTooDeep" - case .commentNotPrecededByWhitespace: - "commentNotPrecededByWhitespace" - case .invalidEscape: - "invalidEscape" - case .malformedDirective: - "malformedDirective" - case .duplicateDirective: - "duplicateDirective" - case .directiveWithoutDocument: - "directiveWithoutDocument" - case .contentAfterDocumentEnd: - "contentAfterDocumentEnd" - case .blockSequenceAsInlineMappingValue: - "blockSequenceAsInlineMappingValue" - case .multilineImplicitKey: - "multilineImplicitKey" - case .commentInMultilineScalar: - "commentInMultilineScalar" - case .aliasWithProperties: - "aliasWithProperties" - case .inlineBlockSequenceAfterProperty: - "inlineBlockSequenceAfterProperty" - case .documentMarkerInScalar: - "documentMarkerInScalar" + case .malformed: + "malformed" } } public var sourceLine: Int? { switch self { - case let .unexpectedIndentation(line), + case .emptyDocument: + nil + case let .tabIndentation(line), + let .unexpectedIndentation(line), let .mixedCollectionStyles(line), + let .expectedMappingKey(line), let .expectedAnchorName(line), let .expectedAliasName(line), let .incompatibleYAMLDirective(line), + let .directiveWithoutDocument(line), let .unterminatedTag(line), let .unterminatedQuotedString(line), let .unsupportedDirective(_, line), - let .unsupportedMultiDocumentStream(line), - let .documentMarkerInScalar(line), - let .invalidEscape(_, line), - let .malformedDirective(_, line), - let .duplicateDirective(_, line), - let .directiveWithoutDocument(line), - let .contentAfterDocumentEnd(line), - let .blockSequenceAsInlineMappingValue(line), - let .multilineImplicitKey(line), - let .commentInMultilineScalar(line): + let .unsupportedMultiDocumentStream(line): line case let .expectedNode(line, _), let .expectedScalarKey(line, _), @@ -186,33 +147,26 @@ public extension PureYAML.Parsing { let .unexpectedEvent(_, _, line, _), let .unexpectedToken(_, _, line, _), let .nestingTooDeep(line, _), - let .commentNotPrecededByWhitespace(line, _), - let .aliasWithProperties(line, _), - let .inlineBlockSequenceAfterProperty(line, _): + let .malformed(_, line, _): line } } public var sourceColumn: Int? { switch self { - case .unexpectedIndentation, + case .emptyDocument, + .tabIndentation, + .unexpectedIndentation, .mixedCollectionStyles, + .expectedMappingKey, .expectedAnchorName, .expectedAliasName, .incompatibleYAMLDirective, + .directiveWithoutDocument, .unterminatedTag, .unterminatedQuotedString, .unsupportedDirective, - .unsupportedMultiDocumentStream, - .documentMarkerInScalar, - .invalidEscape, - .malformedDirective, - .duplicateDirective, - .directiveWithoutDocument, - .contentAfterDocumentEnd, - .blockSequenceAsInlineMappingValue, - .multilineImplicitKey, - .commentInMultilineScalar: + .unsupportedMultiDocumentStream: nil case let .expectedNode(_, column), let .expectedScalarKey(_, column), @@ -222,9 +176,7 @@ public extension PureYAML.Parsing { let .unexpectedEvent(_, _, _, column), let .unexpectedToken(_, _, _, column), let .nestingTooDeep(_, column), - let .commentNotPrecededByWhitespace(_, column), - let .aliasWithProperties(_, column), - let .inlineBlockSequenceAfterProperty(_, column): + let .malformed(_, _, column): column } } diff --git a/Sources/Parsing/Parser.Events.swift b/Sources/Parsing/Parser.Events.swift index 0e8e125..067c318 100644 --- a/Sources/Parsing/Parser.Events.swift +++ b/Sources/Parsing/Parser.Events.swift @@ -1,8 +1,46 @@ extension PureYAML.Parsing.Parser { func parseEvents(_ yaml: String) throws -> [PureYAML.Parsing.Event] { - let tokens = try PureYAML.Parsing.Scanner().scan(yaml) - var parser = PureYAML.Parsing.TokenEventParser(tokens: tokens, scalarParser: self) - return try parser.parse() + let events: [PureYAML.Parsing.Event] + do { + var parser = try PureYAML.Parsing.LibYAML.Parser(yaml) + events = try parser.parse().map { $0.bumpingMark() } + } catch let error as PureYAML.Parsing.LibYAML.ScannerError { + throw PureYAML.Parsing.ParseError(translating: error) + } catch let error as PureYAML.Parsing.LibYAML.ParserError { + throw PureYAML.Parsing.ParseError(translating: error) + } + try enforceNestingLimit(events) + return events + } + + /// The deepest collection nesting the value/event composers will build. The + /// ported parser produces events iteratively without recursion, but the + /// composers, equality, hashing, and `Model/Value` teardown all recurse with + /// the nesting depth, so the event stream is bounded here before any recursive + /// consumer runs. 64 accepts every realistic document yet rejects pathological + /// input well before it can overflow the stack. + static var maxNestingDepth: Int { + 64 + } + + /// Reject an event stream that nests collections past ``maxNestingDepth`` with + /// a ``ParseError/nestingTooDeep(line:column:)`` so deeply nested input fails + /// cleanly instead of overflowing a recursive consumer's stack. + private func enforceNestingLimit(_ events: [PureYAML.Parsing.Event]) throws { + var depth = 0 + for event in events { + switch event { + case .sequenceStart, .mappingStart: + depth += 1 + if depth > Self.maxNestingDepth { + throw PureYAML.Parsing.ParseError.nestingTooDeep(line: event.mark.line, column: event.mark.column) + } + case .sequenceEnd, .mappingEnd: + depth -= 1 + default: + break + } + } } func parseStreaming(_ yaml: String) throws -> PureYAML.Model.Value { @@ -10,14 +48,9 @@ extension PureYAML.Parsing.Parser { scalarParser: self, mode: .singleDocument, ) - var parser = PureYAML.Parsing.TokenEventParser( - yaml: yaml, - scalarParser: self, - eventSink: { event in - try composer.consume(event) - }, - ) - try parser.parseStreaming() + for event in try parseEvents(yaml) { + try composer.consume(event) + } return try composer.composedValue() } @@ -26,14 +59,9 @@ extension PureYAML.Parsing.Parser { scalarParser: self, mode: .stream, ) - var parser = PureYAML.Parsing.TokenEventParser( - yaml: yaml, - scalarParser: self, - eventSink: { event in - try composer.consume(event) - }, - ) - try parser.parseStreaming() + for event in try parseEvents(yaml) { + try composer.consume(event) + } return try composer.composedStream() } @@ -43,14 +71,9 @@ extension PureYAML.Parsing.Parser { mode: .singleDocument, tracksLocations: true, ) - var parser = PureYAML.Parsing.TokenEventParser( - yaml: yaml, - scalarParser: self, - eventSink: { event in - try composer.consume(event) - }, - ) - try parser.parseStreaming() + for event in try parseEvents(yaml) { + try composer.consume(event) + } return try composer.composedLocated() } @@ -60,14 +83,9 @@ extension PureYAML.Parsing.Parser { mode: .stream, tracksLocations: true, ) - var parser = PureYAML.Parsing.TokenEventParser( - yaml: yaml, - scalarParser: self, - eventSink: { event in - try composer.consume(event) - }, - ) - try parser.parseStreaming() + for event in try parseEvents(yaml) { + try composer.consume(event) + } return try composer.composedLocatedStream() } } diff --git a/Sources/Parsing/Parser.ScalarComposition.swift b/Sources/Parsing/Parser.ScalarComposition.swift index 84b973d..1e9aaa8 100644 --- a/Sources/Parsing/Parser.ScalarComposition.swift +++ b/Sources/Parsing/Parser.ScalarComposition.swift @@ -35,6 +35,10 @@ extension PureYAML.Parsing.Parser { 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": diff --git a/Sources/Parsing/Scalar.swift b/Sources/Parsing/Scalar.swift index e82c433..2823967 100644 --- a/Sources/Parsing/Scalar.swift +++ b/Sources/Parsing/Scalar.swift @@ -110,27 +110,8 @@ extension PureYAML.Parsing.Parser { guard text.count >= 2, text.last == "'" else { throw PureYAML.Parsing.ParseError.unterminatedQuotedString(line: line) } - let inner = text.dropFirst().dropLast() - var output = "" - var index = inner.startIndex - while index < inner.endIndex { - let character = inner[index] - if character == "'" { - // A doubled quote escapes to a single quote; a lone quote (not normally present - // inside the stripped body) is kept as-is. - inner.formIndex(after: &index) - output.append("'") - if index < inner.endIndex, inner[index] == "'" { - inner.formIndex(after: &index) - } - } else if character == "\n" || character == "\r" { - foldFlowScalarLineBreaks(in: inner, index: &index, to: &output) - } else { - output.append(character) - inner.formIndex(after: &index) - } - } - return output + let inner = Array(text.dropFirst().dropLast()) + return foldFlowScalar(inner, single: true) } func parseDoubleQuoted( @@ -140,184 +121,238 @@ extension PureYAML.Parsing.Parser { guard text.count >= 2, text.last == "\"" else { throw PureYAML.Parsing.ParseError.unterminatedQuotedString(line: line) } - let inner = text.dropFirst().dropLast() + let inner = Array(text.dropFirst().dropLast()) + return foldFlowScalar(inner, single: false) + } + + /// Flow (quoted) scalar line folding, mirroring libyaml's + /// yaml_parser_scan_flow_scalar (single and double quoted). Trailing + /// whitespace before a break is dropped, leading whitespace on a + /// continuation line is dropped, a single break between non-empty lines + /// folds to one space, and N consecutive breaks yield N-1 line feeds. + /// For double quoted scalars a backslash at end of line suppresses the + /// break entirely. + func foldFlowScalar( + _ inner: [Character], + single: Bool, + ) -> String { + var state = FlowFoldState() + let count = inner.count + while state.index < count { + state.leadingBlanks = false + consumeFlowContent(inner, single: single, state: &state) + consumeFlowBlanks(inner, state: &state) + joinFlowFold(state: &state) + } + return state.output + } + + /// Mutable accumulators for flow scalar folding, matching the C reference's + /// string / leading_break / trailing_breaks / whitespaces buffers. + struct FlowFoldState { var output = "" - var index = inner.startIndex - while index < inner.endIndex { - let character = inner[index] - if character == "\\" { - inner.formIndex(after: &index) - guard index < inner.endIndex else { - output.append("\\") + var whitespaces = "" + var leadingBreak = "" + var trailingBreaks = "" + var leadingBlanks = false + var index = 0 + } + + /// Consume the run of non-blank characters at `state.index`, decoding + /// escapes. A double quoted backslash at end of line sets `leadingBlanks` + /// and stops, so the following break is suppressed during folding. + func consumeFlowContent( + _ inner: [Character], + single: Bool, + state: inout FlowFoldState, + ) { + let count = inner.count + while state.index < count, !isFlowBlank(inner[state.index]), !isFlowBreak(inner[state.index]) { + if single, inner[state.index] == "'" { + state.output.append("'") + let isEscapedQuote = state.index + 1 < count && inner[state.index + 1] == "'" + state.index += isEscapedQuote ? 2 : 1 + continue + } + if !single, inner[state.index] == "\\" { + if state.index + 1 < count, isFlowBreak(inner[state.index + 1]) { + state.index += 2 + state.leadingBlanks = true break } - try appendDoubleQuotedEscape(in: inner, index: &index, to: &output, line: line) - } else if character == "\n" || character == "\r" { - foldFlowScalarLineBreaks(in: inner, index: &index, to: &output) - } else { - output.append(character) - inner.formIndex(after: &index) + state.index += 1 + appendDoubleQuotedEscape(inner, index: &state.index, to: &state.output) + continue } + state.output.append(inner[state.index]) + state.index += 1 } - return output } - /// Flow line folding for a quoted (single- or double-) scalar at a line break. Whitespace - /// adjacent to the break is stripped (the current line's trailing, each following line's - /// leading), then a single break folds to one space and a run of breaks (blank lines) folds to - /// one fewer newline. The scalar's first-line leading whitespace and last-line trailing - /// whitespace are untouched, since they sit next to a quote, not a break. - func foldFlowScalarLineBreaks( - in text: Substring, - index: inout Substring.Index, + /// Consume the run of blanks and line breaks at `state.index`, sorting them + /// into the whitespace / leading-break / trailing-break buffers. + func consumeFlowBlanks( + _ inner: [Character], + state: inout FlowFoldState, + ) { + let count = inner.count + while state.index < count, isFlowBlank(inner[state.index]) || isFlowBreak(inner[state.index]) { + if isFlowBlank(inner[state.index]) { + if !state.leadingBlanks { + state.whitespaces.append(inner[state.index]) + } + } else if !state.leadingBlanks { + state.whitespaces = "" + state.leadingBreak = "\n" + state.leadingBlanks = true + } else { + state.trailingBreaks.append("\n") + } + state.index += 1 + } + } + + /// Join the captured whitespace or fold the captured line breaks into the + /// output, per YAML 1.2 flow folding. + func joinFlowFold(state: inout FlowFoldState) { + guard state.leadingBlanks else { + state.output.append(state.whitespaces) + state.whitespaces = "" + return + } + if state.leadingBreak.first == "\n" { + if state.trailingBreaks.isEmpty { + state.output.append(" ") + } else { + state.output.append(state.trailingBreaks) + state.trailingBreaks = "" + } + state.leadingBreak = "" + } else { + state.output.append(state.leadingBreak) + state.output.append(state.trailingBreaks) + state.leadingBreak = "" + state.trailingBreaks = "" + } + } + + func isFlowBlank(_ character: Character) -> Bool { + character == " " || character == "\t" + } + + func isFlowBreak(_ character: Character) -> Bool { + character == "\n" || character == "\r" || character == "\r\n" + } + + /// Decode a double quoted escape. On entry index points at the escape + /// character (the position just after the backslash). On return index has + /// advanced past every character the escape consumed. The escape set + /// mirrors libyaml's yaml_parser_scan_flow_scalar. + func appendDoubleQuotedEscape( + _ text: [Character], + index: inout Int, to output: inout String, ) { - while let last = output.last, last == " " || last == "\t" { - output.removeLast() + guard index < text.count else { + output.append("\\") + return } - var breaks = 0 - while index < text.endIndex { - let character = text[index] - if character == "\r" { - text.formIndex(after: &index) - if index < text.endIndex, text[index] == "\n" { - text.formIndex(after: &index) - } - breaks += 1 - } else if character == "\n" { - text.formIndex(after: &index) - breaks += 1 - } else if character == " " || character == "\t" { - text.formIndex(after: &index) - } else { - break - } - } - output.append(breaks == 1 ? " " : String(repeating: "\n", count: breaks - 1)) - } - - /// Decodes one double-quoted escape, the character after a `\`. The set is exactly YAML 1.2's - /// escape table; anything else is rejected rather than silently passed through. The index enters - /// at the escape character and is left on the last consumed character, so the caller's trailing - /// advance steps past it. - func appendDoubleQuotedEscape( - in text: Substring, - index: inout Substring.Index, - to output: inout String, - line: Int, - ) throws { let character = text[index] - if let replacement = Self.simpleDoubleQuotedEscapes[character] { - output.append(replacement) - } else { - switch character { - case "x": try appendHexEscape(in: text, index: &index, to: &output, digits: 2, line: line) - case "u": try appendUnicodeEscape(in: text, index: &index, to: &output, line: line) - case "U": try appendHexEscape(in: text, index: &index, to: &output, digits: 8, line: line) - case "\n", "\r": consumeEscapedLineBreak(in: text, index: &index) - default: - throw PureYAML.Parsing.ParseError.invalidEscape(sequence: "\\\(character)", line: line) - } + if let simple = Self.simpleDoubleQuotedEscapes[character] { + output.append(simple) + index += 1 + return + } + switch character { + case "x": + index += 1 + appendHexEscape(text, index: &index, digits: 2, marker: "x", to: &output) + case "u": + index += 1 + appendUnicodeEscape(text, index: &index, to: &output) + case "U": + index += 1 + appendHexEscape(text, index: &index, digits: 8, marker: "U", to: &output) + default: + output.append(character) + index += 1 } - text.formIndex(after: &index) } - /// The YAML 1.2 escapes that map a single character after `\` to one character. Escapes that - /// consume following characters (`\x`, `\u`, `\U`, an escaped line break) are handled separately. + /// Single character double quoted escapes, matching libyaml's escape table. static let simpleDoubleQuotedEscapes: [Character: Character] = [ - "0": "\u{00}", "a": "\u{07}", "b": "\u{08}", "t": "\t", "\t": "\t", - "n": "\n", "v": "\u{0B}", "f": "\u{0C}", "r": "\r", "e": "\u{1B}", - " ": " ", "\"": "\"", "/": "/", "\\": "\\", - "N": "\u{85}", "_": "\u{A0}", "L": "\u{2028}", "P": "\u{2029}", + "0": "\u{00}", + "a": "\u{07}", + "b": "\u{08}", + "t": "\t", + "\t": "\t", + "n": "\n", + "v": "\u{0B}", + "f": "\u{0C}", + "r": "\r", + "e": "\u{1B}", + " ": " ", + "\"": "\"", + "/": "/", + "\\": "\\", + "N": "\u{85}", + "_": "\u{A0}", + "L": "\u{2028}", + "P": "\u{2029}", ] - /// Handles a `\` immediately before a line break: an escaped line break, where the two lines - /// join with no separator. Consumes the break (LF, CR, or CRLF) and the continuation line's - /// leading spaces and tabs, emitting nothing, and leaves the index on the last consumed - /// character so the caller's advance steps to the continuation's first content character. - func consumeEscapedLineBreak( - in text: Substring, - index: inout Substring.Index, - ) { - if text[index] == "\r" { - var next = index - text.formIndex(after: &next) - if next < text.endIndex, text[next] == "\n" { - index = next - } - } - while true { - var next = index - text.formIndex(after: &next) - guard next < text.endIndex, text[next] == " " || text[next] == "\t" else { - break - } - index = next - } - } - - /// Reads a fixed-width hex escape (`\xHH`, `\UHHHHHHHH`) and appends the scalar it denotes, - /// rejecting a truncated sequence or a value that is not a valid Unicode scalar. + /// Decode \xXX or \UXXXXXXXX. On entry index points at the first hex digit. func appendHexEscape( - in text: Substring, - index: inout Substring.Index, - to output: inout String, + _ text: [Character], + index: inout Int, digits: Int, - line: Int, - ) throws { - let typeCharacter = text[index] - guard let value = readHexEscape(in: text, index: &index, digits: digits), - let scalar = UnicodeScalar(value) - else { - throw PureYAML.Parsing.ParseError.invalidEscape(sequence: "\\\(typeCharacter)", line: line) + marker: Character, + to output: inout String, + ) { + guard let value = readHex(text, index: &index, digits: digits) else { + output.append(marker) + return + } + if let scalar = UnicodeScalar(value) { + output.unicodeScalars.append(scalar) + } else { + output.append(marker) } - output.unicodeScalars.append(scalar) } + /// Decode \uXXXX, including surrogate pairs. On entry index points at the + /// first hex digit. func appendUnicodeEscape( - in text: Substring, - index: inout Substring.Index, + _ text: [Character], + index: inout Int, to output: inout String, - line: Int, - ) throws { - guard let codeUnit = readHexEscape(in: text, index: &index, digits: 4) else { - throw PureYAML.Parsing.ParseError.invalidEscape(sequence: "\\u", line: line) + ) { + let start = index + guard let codeUnit = readHex(text, index: &index, digits: 4) else { + output.append("u") + index = start + return } - if let scalar = readSurrogatePairIfNeeded(high: codeUnit, in: text, index: &index) { + if isHighSurrogate(codeUnit), let scalar = readSurrogatePair(high: codeUnit, text: text, index: &index) { output.unicodeScalars.append(scalar) } else if let scalar = UnicodeScalar(codeUnit) { output.unicodeScalars.append(scalar) } else { - throw PureYAML.Parsing.ParseError.invalidEscape(sequence: "\\u", line: line) + output.append("u") } } - func readSurrogatePairIfNeeded( - high: UInt32, - in text: Substring, - index: inout Substring.Index, - ) -> UnicodeScalar? { - guard isHighSurrogate(high) else { - return nil - } - return readSurrogatePair(high: high, in: text, index: &index) - } - func readSurrogatePair( high: UInt32, - in text: Substring, - index: inout Substring.Index, + text: [Character], + index: inout Int, ) -> UnicodeScalar? { var probe = index - text.formIndex(after: &probe) - guard probe < text.endIndex, text[probe] == "\\" else { + guard probe + 1 < text.count, text[probe] == "\\", text[probe + 1] == "u" else { return nil } - text.formIndex(after: &probe) - guard probe < text.endIndex, text[probe] == "u", - let low = readHexEscape(in: text, index: &probe, digits: 4), - isLowSurrogate(low) - else { + probe += 2 + guard let low = readHex(text, index: &probe, digits: 4), isLowSurrogate(low) else { return nil } index = probe @@ -325,26 +360,25 @@ extension PureYAML.Parsing.Parser { return UnicodeScalar(value) } - /// Reads `digits` hex characters following the escape type character. The index enters at the - /// type character and is left on the final hex digit; returns nil if fewer than `digits` hex - /// characters are available. - func readHexEscape( - in text: Substring, - index: inout Substring.Index, + /// Read exactly `digits` hex characters starting at index. On success index + /// advances past them, otherwise index is left unchanged. + func readHex( + _ text: [Character], + index: inout Int, digits: Int, ) -> UInt32? { - var probe = index - text.formIndex(after: &probe) - var hex = "" - for _ in 0 ..< digits { - guard probe < text.endIndex, text[probe].isHexDigit else { + guard index + digits <= text.count else { + return nil + } + var value: UInt32 = 0 + for offset in 0 ..< digits { + guard let digit = text[index + offset].hexDigitValue else { return nil } - hex.append(text[probe]) - text.formIndex(after: &probe) + value = (value << 4) + UInt32(digit) } - index = text.index(before: probe) - return UInt32(hex, radix: 16) + index += digits + return value } func isHighSurrogate(_ value: UInt32) -> Bool { diff --git a/Sources/Parsing/Scanner.Directives.swift b/Sources/Parsing/Scanner.Directives.swift deleted file mode 100644 index 29d44d6..0000000 --- a/Sources/Parsing/Scanner.Directives.swift +++ /dev/null @@ -1,167 +0,0 @@ -extension PureYAML.Parsing.Scanner { - func scanDirectiveOrDocumentMarker(_ state: inout State) throws -> Bool { - guard state.indentation.last == 0 else { - return false - } - // A `%` opens a directive only outside a block scalar. Inside one (a zero-indent literal or - // folded scalar sits at column 0, where this directive check runs) a leading `%` is literal - // content, so let the main scanner read the line. Elsewhere the directive path still runs, so - // a stray `%` in other content is rejected as before, not silently accepted. - if state.reader.peek() == "%", state.blockScalarIndentation == nil { - try scanDirective(&state) - return true - } - if state.reader.peek() == "#" { - return false - } - if startsWith("---", state.reader), isIndicatorBoundary(state.reader.peek(offset: 3)) { - try scanDocumentMarker(.documentStart, state: &state) - resetForDocumentStart(&state) - return true - } - if startsWith("...", state.reader), isIndicatorBoundary(state.reader.peek(offset: 3)) { - // A `...` after a document is already closed (only comments or blank lines since the - // last `...`) ends nothing: it is a repeated document-end marker, which YAML allows. Skip - // it as a no-op rather than emitting a second documentEnd (which would compose a phantom - // null document) or rejecting a valid stream. Content after it is still an error. - if state.isDocumentClosed { - state.reader.advance() - state.reader.advance() - state.reader.advance() - while state.reader.peek() == " " { - state.reader.advance() - } - if let next = state.reader.peek(), !isLineBreak(next), next != "#" { - throw PureYAML.Parsing.ParseError.contentAfterDocumentEnd(line: state.reader.mark.line) - } - skipLine(&state) - return true - } - // A `...` ends a document, so a directive still awaiting its `---` never gets one. - try enforceDirectiveHasDocument(state) - try scanDocumentMarker(.documentEnd, state: &state) - resetForDocumentEnd(&state) - return true - } - // Content after a document-end marker (`...`) begins a new bare document, so reopen the - // stream rather than rejecting it. - if state.isDocumentClosed { - state.isDocumentClosed = false - } - return false - } - - func scanDocumentMarker( - _ kind: PureYAML.Parsing.TokenKind, - state: inout State, - ) throws { - let start = state.reader.mark - state.reader.advance() - state.reader.advance() - state.reader.advance() - state.append(kind, mark: start, endMark: state.reader.mark) - while state.reader.peek() == " " { - state.reader.advance() - } - if let next = state.reader.peek(), !isLineBreak(next), next != "#" { - // The marker's own line carries real content. A document start may carry the root node - // here (e.g. `--- >`, `--- foo`, `--- {a: 1}`), so leave it for the main loop to scan. - if case .documentStart = kind { - state.isAtLineStart = false - return - } - // A document end (`...`) takes no same-line node; only a comment or blank may follow it. - throw PureYAML.Parsing.ParseError.contentAfterDocumentEnd(line: state.reader.mark.line) - } - skipLine(&state) - } - - func resetForDocumentStart(_ state: inout State) { - state.hasDocumentContent = false - state.hasDocumentStartMarker = true - state.isDocumentClosed = false - state.hasYAMLDirective = false - state.pendingDirectiveLine = nil - // The directives that preceded this `---` apply to this document only: merge them onto the - // defaults, then clear them so they do not leak into the next document. - state.tagHandles = State.defaultTagHandles.merging(state.pendingTagHandles) { _, new in new } - state.pendingTagHandles = [:] - } - - /// A directive must be followed by an explicit `---` document start. Called at a document end - /// and at stream end, where a still-pending directive means none ever came. - func enforceDirectiveHasDocument(_ state: State) throws { - if let line = state.pendingDirectiveLine { - throw PureYAML.Parsing.ParseError.directiveWithoutDocument(line: line) - } - } - - func resetForDocumentEnd(_ state: inout State) { - state.hasDocumentContent = false - state.hasDocumentStartMarker = false - state.isDocumentClosed = true - state.hasYAMLDirective = false - // A document boundary ends the scope of that document's tag handles. - state.tagHandles = State.defaultTagHandles - state.pendingTagHandles = [:] - } - - func scanDirective(_ state: inout State) throws { - let start = state.reader.mark - let line = state.reader.consume { character in - !isLineBreak(character) - } - let parts = line.split(separator: " ").map(String.init) - guard let name = parts.first else { - return - } - // A directive after a document-end marker (`...`) begins the next document's directive - // section, so it reopens the stream for a new document rather than being rejected. - if state.isDocumentClosed { - state.isDocumentClosed = false - } - guard !state.hasDocumentContent, !state.hasDocumentStartMarker else { - throw PureYAML.Parsing.ParseError.unsupportedDirective(name: name, line: start.line) - } - // Every directive must be followed by an explicit `---`; record that one is now awaiting it. - state.pendingDirectiveLine = start.line - switch name { - case "%YAML": - // Any version with major 1 is processable: a higher minor than 1.2 (`%YAML 1.3`) is - // accepted, since the spec calls for processing it, with a warning, rather than rejecting - // it. Only a different major version, or a malformed one, is incompatible. - guard parts.indices.contains(1), isProcessableYAMLVersion(parts[1]) else { - throw PureYAML.Parsing.ParseError.incompatibleYAMLDirective(line: start.line) - } - // `%YAML` takes exactly one parameter, the version; only a comment may follow it. - guard parts.count == 2 || parts[2].hasPrefix("#") else { - throw PureYAML.Parsing.ParseError.malformedDirective(name: name, line: start.line) - } - // At most one `%YAML` directive is allowed per document. - guard !state.hasYAMLDirective else { - throw PureYAML.Parsing.ParseError.duplicateDirective(name: name, line: start.line) - } - state.hasYAMLDirective = true - case "%TAG": - guard parts.count >= 3 else { - return - } - state.pendingTagHandles[parts[1]] = parts[2] - default: - // A YAML processor ignores a directive it does not recognize (the spec calls for a - // warning and otherwise no effect), rather than rejecting the document. The line has - // already been consumed, so there is nothing more to do. - return - } - } - - /// Whether a `%YAML` version is one this processor can attempt: any `major.minor` with major 1, - /// so 1.0 through 1.2 and a higher minor like 1.3 are all accepted; a different major (2.0) or a - /// non-numeric version is not. - func isProcessableYAMLVersion(_ version: String) -> Bool { - let components = version.split(separator: ".", omittingEmptySubsequences: false) - return components.count == 2 - && components[0] == "1" - && components.allSatisfy { !$0.isEmpty && $0.allSatisfy(\.isNumber) } - } -} diff --git a/Sources/Parsing/Scanner.FlowContext.swift b/Sources/Parsing/Scanner.FlowContext.swift deleted file mode 100644 index c8b5ef5..0000000 --- a/Sources/Parsing/Scanner.FlowContext.swift +++ /dev/null @@ -1,11 +0,0 @@ -extension PureYAML.Parsing { - struct ScannerFlowContext { - var kind: ScannerFlowContextKind - var isExpectingKey: Bool - /// Whether an explicit key indicator (`?`) is open at this flow level, so the following scalar - /// is the explicit key's content and must not synthesize its own implicit key. Cleared by the - /// pair's `:` value indicator or a `,`, and discarded with the context when the collection - /// closes, so it tracks per-level and a nested collection's `:` does not affect an outer key. - var hasExplicitKey = false - } -} diff --git a/Sources/Parsing/Scanner.FlowKey.swift b/Sources/Parsing/Scanner.FlowKey.swift deleted file mode 100644 index f49b0d1..0000000 --- a/Sources/Parsing/Scanner.FlowKey.swift +++ /dev/null @@ -1,89 +0,0 @@ -extension PureYAML.Parsing.Scanner { - /// Emits the implicit-key marker before a block-level flow collection that a `: ` follows, so the - /// flow node is parsed as a mapping key (e.g. `[a, b]: value`) through the same path a scalar key - /// takes. Skipped inside a flow context, after a mapping value already on the line (block style - /// allows one pair per line), and under a pending explicit `?` key, which marks its own key. - func appendFlowImplicitKeyMarkerIfNeeded(state: inout State) { - guard state.flowDepth == 0, !state.sawMappingValueOnLine, !state.pendingExplicitKey, - flowCollectionIsImplicitKey(state: state) - else { - return - } - let mark = state.reader.mark - state.append(.mappingKey, mark: mark, endMark: mark) - } - - /// Looks ahead from a block-level flow collection opener (`[` or `{`) to decide whether the whole - /// collection is an implicit mapping key: a flow node immediately followed by a `: ` mapping-value - /// indicator, e.g. `[a, b]: value` or `{a: 1}: value`. Quoted scalars are skipped so brackets and - /// colons inside them do not affect the nesting count, and the `:` must sit on the same line as - /// the close (only spaces between), since a block implicit key carries its `:` on its own line. - /// Returns false if the brackets do not balance before end of input. - func flowCollectionIsImplicitKey(state: State) -> Bool { - var depth = 0 - var offset = 0 - while let character = state.reader.peek(offset: offset) { - // A block implicit key must lie on a single line, so a flow collection that spans a line - // break (outside any quoted scalar) before its `:` cannot be one: `[23\n]: 42` is an error. - if isLineBreak(character) { - return false - } - switch character { - case "'": - offset = skipSingleQuotedLookahead(after: offset, state: state) - case "\"": - offset = skipDoubleQuotedLookahead(after: offset, state: state) - case "[", "{": - depth += 1 - offset += 1 - case "]", "}": - depth -= 1 - offset += 1 - guard depth > 0 else { - while state.reader.peek(offset: offset) == " " { - offset += 1 - } - return state.reader.peek(offset: offset) == ":" - && isBlockMappingValueBoundary(state.reader.peek(offset: offset + 1)) - } - default: - offset += 1 - } - } - return false - } - - /// Returns the offset just past the closing `'` of a single-quoted scalar that opened at `open`, - /// treating a doubled `''` as an escaped quote rather than a close. - private func skipSingleQuotedLookahead(after open: Int, state: State) -> Int { - var offset = open + 1 - while let character = state.reader.peek(offset: offset) { - if character == "'" { - if state.reader.peek(offset: offset + 1) == "'" { - offset += 2 - continue - } - return offset + 1 - } - offset += 1 - } - return offset - } - - /// Returns the offset just past the closing `"` of a double-quoted scalar that opened at `open`, - /// skipping `\`-escaped characters so an escaped quote does not end the scan early. - private func skipDoubleQuotedLookahead(after open: Int, state: State) -> Int { - var offset = open + 1 - while let character = state.reader.peek(offset: offset) { - if character == "\\" { - offset += 2 - continue - } - if character == "\"" { - return offset + 1 - } - offset += 1 - } - return offset - } -} diff --git a/Sources/Parsing/Scanner.Helpers.swift b/Sources/Parsing/Scanner.Helpers.swift deleted file mode 100644 index ea1985f..0000000 --- a/Sources/Parsing/Scanner.Helpers.swift +++ /dev/null @@ -1,379 +0,0 @@ -extension PureYAML.Parsing.Scanner { - /// A blank line inside a block scalar is preserved as empty content so that - /// chomping and folding can apply to it. The guard keeps blank lines outside - /// block scalars unaffected; `isAtLineStart` is true here only when the - /// previous line already ended, so a content line's own terminating break - /// does not emit a blank. Blank lines between the header and the first - /// content line precede the indent token, so they are buffered and emitted - /// once the content indentation is established. - func captureBlockScalarBlankLine(_ state: inout State) { - guard state.isAtLineStart else { - return - } - if state.blockScalarIndentation != nil { - // The prefix holds any surplus indentation past the block's content level for an - // otherwise-empty line (see `preserveBlockScalarSurplusOnBlankLine`); empty otherwise. - state.append(.scalar(value: state.blockScalarContentPrefix, style: .plain)) - state.blockScalarContentPrefix = "" - } else if state.pendingBlockScalarIndentation { - state.pendingBlockScalarLeadingBlankWhitespace.append(state.lastLeadingWhitespace) - } - } - - func startsWith( - _ prefix: String, - _ reader: PureYAML.Parsing.Reader, - ) -> Bool { - for (offset, character) in prefix.enumerated() { - guard reader.peek(offset: offset) == character else { - return false - } - } - return true - } - - func isLineBreak(_ character: Character?) -> Bool { - character == "\n" || character == "\r" || character == "\r\n" - } - - func isBlockEntry(_ reader: PureYAML.Parsing.Reader) -> Bool { - reader.peek() == "-" && isIndicatorBoundary(reader.peek(offset: 1)) - } - - func isIndicatorBoundary(_ character: Character?) -> Bool { - guard let character else { - return true - } - // A tab is separation white space in YAML (only indentation forbids it), so it ends an - // indicator just as a space does: `---\tscalar`, `-\titem`, `?\tkey`. - return character == " " || character == "\t" || isLineBreak(character) - } - - func isMappingValueBoundary(_ character: Character?) -> Bool { - guard let character else { - return true - } - // A tab is separation white space, so it follows a `:` value indicator as a space does. - return character == " " - || character == "\t" - || isLineBreak(character) - || character == "," - || character == "]" - || character == "}" - } - - func isBlockMappingValueBoundary(_ character: Character?) -> Bool { - guard let character else { - return true - } - return character == " " || character == "\t" || isLineBreak(character) - } - - func isTokenTerminator(_ character: Character) -> Bool { - character == " " - || isLineBreak(character) - || character == "," - || character == "[" - || character == "]" - || character == "{" - || character == "}" - || character == "#" - } - - func canStartAnchorName(_ character: Character?) -> Bool { - guard let character else { - return false - } - return !isTokenTerminator(character) - && character != "*" - && character != "&" - && character != "!" - && character != "\"" - && character != "'" - } - - func hasNodeOnSameLine(afterCurrentPositionIn reader: PureYAML.Parsing.Reader) -> Bool { - var offset = 0 - while reader.peek(offset: offset) == " " { - offset += 1 - } - guard let character = reader.peek(offset: offset) else { - return false - } - return !isLineBreak(character) && character != "#" - } - - func isFlowDelimiter(_ character: Character) -> Bool { - character == "," - || character == "[" - || character == "]" - || character == "{" - || character == "}" - } - - func isBlockScalarHeaderCharacter(_ character: Character) -> Bool { - character == "+" - || character == "-" - || character.isNumber - } - - func trimTrailingSpaces(_ value: String) -> String { - var end = value.endIndex - while end > value.startIndex { - let previous = value.index(before: end) - guard value[previous] == " " else { - break - } - end = previous - } - return String(value[.. String { - var value = firstLine - while true { - var probe = state.reader - guard isLineBreak(probe.peek()) else { - return value - } - - probe.advance() - let blankLineCount = consumeBlankLines(&probe) - - _ = probe.consume { character in - character == " " - } - let indentationWidth = probe.mark.column - 1 - - guard !probe.isAtEnd, !isLineBreak(probe.peek()), probe.peek() != "#" else { - return value - } - - // A plain scalar never spans a document marker (`---` / `...`); stop the continuation at - // one so it begins (or ends) the document rather than folding into the scalar's value. - if indentationWidth == 0, isAtDocumentMarker(probe) { - return value - } - - let baseIndentation = plainScalarContinuationBaseIndentation(state: state, firstLineIndent: firstLineIndent) - guard indentationWidth > baseIndentation else { - return value - } - if isBlockEntry(probe), state.validImplicitIndentation.contains(indentationWidth) { - return value - } - - var continuationState = state - continuationState.reader = probe - let continuation = scanPlainScalarContinuationLine(&continuationState) - if isAtMappingValueIndicator(state: continuationState) { - // A continuation line ending at `:` is normally a new implicit key, so the scalar - // stops before it. Two cases keep folding instead, with the `:` left to be scanned as - // the value indicator: a block explicit key (`? foo` then `bar :`), where the line is - // still the key's content, and any flow scalar, since a flow key may span lines - // (`{ multi`/`line: v }`) where a block implicit key may not. - let foldsAcrossMappingValue = state.flowDepth > 0 || state.pendingExplicitKey - guard foldsAcrossMappingValue else { - return value - } - state = continuationState - value += blankLineCount == 0 ? " " : String(repeating: "\n", count: blankLineCount) - value += continuation - return value - } - - state = continuationState - if blankLineCount == 0 { - value += " " - } else { - value += String(repeating: "\n", count: blankLineCount) - } - value += continuation - } - } - - /// Advance `probe` over a run of blank lines (lines that are empty or only spaces), returning - /// how many were consumed; the probe is left at the start of the next non-blank line. - func consumeBlankLines(_ probe: inout PureYAML.Parsing.Reader) -> Int { - var count = 0 - while true { - var blankProbe = probe - // A line of only white space is empty for folding, including one that holds a tab: a tab - // is not indentation, but a whitespace-only line is still blank, so consume it here. - _ = blankProbe.consume { character in - character == " " || character == "\t" - } - guard isLineBreak(blankProbe.peek()) else { - break - } - blankProbe.advance() - probe = blankProbe - count += 1 - } - return count - } - - /// Whether the reader is positioned at a document marker (`---` or `...`) followed by an - /// indicator boundary, i.e. the marker that starts or ends a document. - func isAtDocumentMarker(_ reader: PureYAML.Parsing.Reader) -> Bool { - (startsWith("---", reader) || startsWith("...", reader)) && isIndicatorBoundary(reader.peek(offset: 3)) - } - - func plainScalarContinuationBaseIndentation(state: State, firstLineIndent: Int) -> Int { - // When the scalar begins exactly at the current indentation top, it is a block value on its - // own line, so its own indent was pushed onto the stack; its continuation lines sit at that - // same indent, and the level they must exceed is the enclosing block's: the indent below on - // the stack, or -1 at the document root, where nothing encloses the scalar and a - // continuation may sit at column 1. For an inline value the top of the stack already is the - // enclosing block's indent, so it is used directly. - if state.indentation.last == firstLineIndent { - return state.indentation.count >= 2 ? state.indentation[state.indentation.count - 2] : -1 - } - return state.indentation.last ?? 0 - } - - func scanPlainScalarContinuationLine(_ state: inout State) -> String { - // Leading white space beyond the line's indentation folds away in a plain scalar. A tab is - // not indentation, so the indentation scan leaves it here; skip it (and any spaces after it) - // so a continuation line like `\t3rd` joins as `3rd`, not `\t3rd`. - while let character = state.reader.peek(), character == " " || character == "\t" { - state.reader.advance() - } - var value = "" - while let character = state.reader.peek(), !isLineBreak(character) { - if character == " ", state.reader.peek(offset: 1) == "#" { - break - } - if character == "#", value.isEmpty || value.last == " " { - break - } - if character == ":", shouldEndPlainScalarAtMappingValue(state: state) { - break - } - if state.flowDepth > 0, isFlowDelimiter(character) { - break - } - value.append(character) - state.reader.advance() - } - return trimTrailingSpaces(value) - } - - func skipLine(_ state: inout State) { - _ = state.reader.consume { character in - !isLineBreak(character) - } - } - - func shouldEndPlainScalar( - _ character: Character, - state: State, - accumulated: String, - ) -> Bool { - if isLineBreak(character) { - return true - } - // A comment opens after white space, a tab as well as a space, so a `#` preceded by either - // ends the plain scalar: `d\t#X` is the value `d` with a trailing comment. - if character == " " || character == "\t", state.reader.peek(offset: 1) == "#" { - return true - } - if character == "#", accumulated.isEmpty || accumulated.last == " " || accumulated.last == "\t" { - return true - } - if character == ":", shouldEndPlainScalarAtMappingValue(state: state) { - return true - } - if state.flowDepth > 0, isFlowDelimiter(character) { - return true - } - return false - } - - func shouldEndPlainScalarAtMappingValue(state: State) -> Bool { - if state.flowDepth > 0 { - return state.isExpectingFlowMappingKey - || isMappingValueBoundary(state.reader.peek(offset: 1)) - } - return isBlockMappingValueBoundary(state.reader.peek(offset: 1)) - } - - func isAtMappingValueIndicator(state: State) -> Bool { - state.reader.peek() == ":" && shouldEndPlainScalarAtMappingValue(state: state) - } - - /// Whether a mapping-value indicator (`: ` or `:` at line end) follows, allowing spaces before - /// the colon. Used after a quoted scalar, where the reader stops at the closing quote and any - /// separating spaces remain, unlike a plain scalar that ends at the colon itself. - func isAtMappingValueIndicatorAfterSpaces(state: State) -> Bool { - var offset = 0 - while state.reader.peek(offset: offset) == " " { - offset += 1 - } - return state.reader.peek(offset: offset) == ":" - && isBlockMappingValueBoundary(state.reader.peek(offset: offset + 1)) - } - - @discardableResult - func appendMappingKeyIfNeeded( - start: PureYAML.Parsing.Mark, - state: inout State, - ) -> Bool { - guard isAtMappingValueIndicator(state: state), canSynthesizeImplicitBlockKey(state) else { - return false - } - state.append(.mappingKey, mark: start, endMark: start) - return true - } - - /// Whether a scalar followed by `:` may start an implicit mapping key here. In block style a - /// line holds at most one mapping pair, so once a block-level `:` has appeared on the line a - /// further key would form a forbidden inline nested mapping; in flow style several pairs per - /// line are allowed, so that restriction does not apply. In flow a scalar that is the content of - /// an open explicit key (`?`) is the key itself, not a new implicit key. - /// Records the implicit indentation levels a block entry with an inline node introduces: the - /// node's own indent (one past the dash), and the dash's indent as a sibling level so an inline - /// item's plain value stops folding at a later entry that returns to it (`: -␣b` then ` - - c`). - /// The sibling level is skipped under a pending explicit key (`? - x`), whose sequence key drives - /// implicit indentation itself. - func recordBlockEntryImplicitIndentation(start: PureYAML.Parsing.Mark, state: inout State) { - guard hasNodeOnSameLine(afterCurrentPositionIn: state.reader) else { - return - } - state.validImplicitIndentation.insert(start.column + 1) - if !state.pendingExplicitKey { - state.validImplicitIndentation.insert(start.column - 1) - } - } - - func canSynthesizeImplicitBlockKey(_ state: State) -> Bool { - if state.flowDepth > 0 { - return state.flowContexts.last?.hasExplicitKey != true - } - return !state.sawMappingValueOnLine - } - - /// A `:` with no node before it on the line is an implicit empty mapping key, unless it is the - /// value indicator of a pending explicit `?` key. This covers both a bare `: value` and a line - /// whose only prior content is a node property (`&a : value`, `!!str : value`): the property - /// decorates the empty key, which the preceding property tokens bind to. Synthesizes the empty - /// key and its node so the block mapping machinery treats the pair uniformly. - func synthesizeNullMappingKeyIfNeeded( - _ character: Character, - hadNonPropertyContentOnLine: Bool, - state: inout State, - ) { - guard character == ":", !hadNonPropertyContentOnLine, state.flowDepth == 0, - !state.pendingExplicitKey, isAtMappingValueIndicator(state: state) - else { - return - } - let mark = state.reader.mark - state.append(.mappingKey, mark: mark, endMark: mark) - state.append(.scalar(value: "", style: .plain), mark: mark, endMark: mark) - } -} diff --git a/Sources/Parsing/Scanner.Indentation.swift b/Sources/Parsing/Scanner.Indentation.swift deleted file mode 100644 index fc101c6..0000000 --- a/Sources/Parsing/Scanner.Indentation.swift +++ /dev/null @@ -1,312 +0,0 @@ -extension PureYAML.Parsing.Scanner { - func scanIndentation(_ state: inout State) throws { - let start = state.reader.mark - let width = try scanIndentationWidth(&state) - guard shouldProcessIndentation(state) else { - preserveBlockScalarSurplusOnBlankLine(width: width, state: &state) - recordPendingBlockScalarBlankIndent(width: width, state: &state) - return - } - - let end = state.reader.mark - let current = state.indentation.last ?? 0 - let wasInBlockScalar = state.blockScalarIndentation != nil - - // A document marker (`---` / `...`) at column 0 ends an active block scalar rather than - // being its content. Close the scalar's indentation here, dedenting back to the document - // level, so the marker is then scanned balanced at the document level. Without this the - // scalar's indent lingers past the marker and surfaces later as a stray dedent plus a - // phantom empty node (the marker still ends the document, but the structure is unbalanced). - if state.blockScalarIndentation != nil, width == 0, isAtDocumentMarker(state.reader) { - state.blockScalarIndentation = nil - state.blockScalarContentPrefix = "" - while state.indentation.count > 1 { - state.indentation.removeLast() - state.append(.dedent(width: state.indentation.last ?? 0), mark: end, endMark: end) - } - return - } - - if consumeBlockScalarContentIndentation(width: width, state: &state) { - return - } - - // An active block scalar that just ended (its content was less indented this line) onto a - // line beginning with '#' is leaving an ordinary comment. A comment's own indentation does - // not participate in block structure, so leave it for the main loop to scan rather than - // forcing its column to match an indentation level, which would dedent onto a width no stack - // level holds and raise a spurious error. The guard on `wasInBlockScalar` keeps a block - // scalar's own first content line that begins with '#' (e.g. `|-` then `# text`) as content. - if wasInBlockScalar, state.reader.peek() == "#" { - return - } - - if let indicator = state.pendingBlockScalarIndentationIndicator { - try applyExplicitBlockScalarIndentation( - indicator: indicator, - width: width, - current: current, - marks: (start: start, end: end), - state: &state, - ) - } else if width > current { - try applyIncreasedIndentation(width: width, start: start, end: end, state: &state) - } else if state.pendingBlockScalarIndentation, state.pendingBlockScalarIsRootNode, width == current { - // A root block scalar (`>`/`|` as the whole document) has the document node as its - // parent, whose indentation is -1, so content at column 0 (width == current == 0) is - // still more indented than its parent and must establish the block scalar's content - // indentation here, where `width > current` (with the base level read as 0) cannot fire. - // A non-root block scalar (a sequence item or mapping value) keeps its parent's indent as - // the floor, so its under-indented content still falls through to an error, unchanged. - try applyIncreasedIndentation(width: width, start: start, end: end, state: &state) - } else if width < current { - try applyDedentation(width: width, start: start, end: end, state: &state) - } - - pruneImplicitIndentation(&state) - clearPendingBlockScalarIndentation(&state) - } - - /// Records a leading blank line's indentation while a block scalar's content indentation is - /// still pending (before its first content line), so an over-indented leading line can be - /// caught once the content indentation is established. - func recordPendingBlockScalarBlankIndent(width _: Int, state: inout State) { - guard state.pendingBlockScalarIndentation, state.blockScalarIndentation == nil else { - return - } - // Compare leading spaces, not the tab-expanded width: a tab on a blank line is not - // indentation, so `␣\t` counts as one space, not a jump to the next tab stop. - state.pendingBlockScalarMaxBlankIndent = max(state.pendingBlockScalarMaxBlankIndent, state.lastLeadingSpaceCount) - } - - /// A block scalar's leading empty lines must not be more indented than its content, so reject - /// the scalar if the widest leading blank exceeds the content indentation. - func enforceLeadingBlankIndentation(contentIndent: Int, line: Int, state: State) throws { - guard state.pendingBlockScalarMaxBlankIndent > contentIndent else { - return - } - throw PureYAML.Parsing.ParseError.unexpectedIndentation(line: line) - } - - /// A whitespace-only line inside an active block scalar that is indented past the block's - /// content indentation carries the surplus spaces as content (e.g. a 3-space line in a 2-space - /// block contributes `" "`). The width is consumed before the line is recognized as blank, so - /// stash the surplus in the content prefix for the blank-line emission to pick up; otherwise the - /// line collapses to empty and a space is dropped from the scalar's value. - func preserveBlockScalarSurplusOnBlankLine(width: Int, state: inout State) { - guard let blockScalarIndentation = state.blockScalarIndentation, width > blockScalarIndentation else { - return - } - state.blockScalarContentPrefix = blockScalarSurplusPrefix(beyond: blockScalarIndentation, whitespace: state.lastLeadingWhitespace) - } - - func scanIndentationWidth(_ state: inout State) throws -> Int { - var width = 0 - var leadingSpaces = 0 - var sawTab = false - var whitespace = "" - while let character = state.reader.peek() { - if character == " " { - width += 1 - if !sawTab { - leadingSpaces += 1 - } - whitespace.append(character) - state.reader.advance() - } else if character == "\t" { - sawTab = true - width = nextTabStop(after: width) - whitespace.append(character) - state.reader.advance() - } else { - break - } - } - state.lastLeadingSpaceCount = leadingSpaces - state.lastLeadingWhitespace = whitespace - return width - } - - func nextTabStop(after width: Int) -> Int { - ((width / 4) + 1) * 4 - } - - /// The leading-whitespace characters that lie beyond a block scalar's space-only `indent`, kept - /// verbatim so a tab in the content (` \ttext` under a 2-space indent) stays a tab rather than - /// being re-expanded to spaces. Walks the recorded whitespace, counting columns the way the width - /// scan does, and returns the remainder once the indentation columns are covered. - func blockScalarSurplusPrefix(beyond indent: Int, whitespace: String) -> String { - var column = 0 - var index = whitespace.startIndex - while index < whitespace.endIndex, column < indent { - let character = whitespace[index] - column = character == "\t" ? nextTabStop(after: column) : column + 1 - index = whitespace.index(after: index) - } - return String(whitespace[index...]) - } - - func shouldProcessIndentation(_ state: State) -> Bool { - guard !state.reader.isAtEnd, !isLineBreak(state.reader.peek()) else { - return false - } - // A leading '#' normally starts a comment line, which must not drive - // indent/dedent processing. Inside a block scalar it is different: when - // the header is still pending or the content is active, a leading '#' is - // literal scalar content, so indentation must be processed so the block - // scalar's indentation resolves and its content lines are consumed. - // Bailing here would leave `blockScalarIndentation` unset and the main - // loop would mis-scan the line as a comment, dropping the content. - if state.reader.peek() == "#", !state.pendingBlockScalarIndentation, state.blockScalarIndentation == nil { - return false - } - return state.flowDepth == 0 - } - - func consumeBlockScalarContentIndentation( - width: Int, - state: inout State, - ) -> Bool { - guard let blockScalarIndentation = state.blockScalarIndentation else { - return false - } - guard width < blockScalarIndentation else { - state.blockScalarContentPrefix = blockScalarSurplusPrefix(beyond: blockScalarIndentation, whitespace: state.lastLeadingWhitespace) - return true - } - state.blockScalarIndentation = nil - state.blockScalarContentPrefix = "" - return false - } - - func applyExplicitBlockScalarIndentation( - indicator: Int, - width: Int, - current: Int, - marks: (start: PureYAML.Parsing.Mark, end: PureYAML.Parsing.Mark), - state: inout State, - ) throws { - // The indicator is the content indentation relative to the block scalar's parent node. For an - // inline mapping value (`- aaa: |2`), the parent mapping sits at an implicit indentation that - // never reached the main stack, so take the deepest applicable implicit level as the base: - // `|2` under a mapping at column 2 makes the content indentation 4. A direct sequence item - // (`- |2`) has no such parent and keeps the stack's current level. - let parentIndentation = state.pendingBlockScalarInlineMappingValue - ? max(current, state.validImplicitIndentation.filter { $0 <= width }.max() ?? current) - : current - let blockScalarIndentation = parentIndentation + indicator - guard width >= blockScalarIndentation else { - throw PureYAML.Parsing.ParseError.unexpectedIndentation(line: marks.end.line) - } - try enforceLeadingBlankIndentation(contentIndent: blockScalarIndentation, line: marks.end.line, state: state) - state.indentation.append(blockScalarIndentation) - state.append(.indent(width: blockScalarIndentation), mark: marks.start, endMark: marks.end) - state.blockScalarIndentation = blockScalarIndentation - state.blockScalarContentPrefix = String(repeating: " ", count: width - blockScalarIndentation) - emitBufferedBlockScalarLeadingBlanks(&state) - clearPendingBlockScalarIndentation(&state) - } - - /// Leading blank lines (between the header and the first content line) are - /// buffered until the indent token is emitted, then flushed as empty content - /// so they land after the indent and before the first content line. - func emitBufferedBlockScalarLeadingBlanks(_ state: inout State) { - // Each leading blank line carries any whitespace past the (now known) content indentation as - // content: an otherwise-blank `␣\t` line under a one-space indent yields the tab. With no - // content indentation established (an empty block scalar), the line is simply empty. - let indent = state.blockScalarIndentation - for whitespace in state.pendingBlockScalarLeadingBlankWhitespace { - let surplus = indent.map { blockScalarSurplusPrefix(beyond: $0, whitespace: whitespace) } ?? "" - state.append(.scalar(value: surplus, style: .plain)) - } - state.pendingBlockScalarLeadingBlankWhitespace = [] - } - - func applyIncreasedIndentation( - width: Int, - start: PureYAML.Parsing.Mark, - end: PureYAML.Parsing.Mark, - state: inout State, - ) throws { - guard state.pendingBlockScalarIndentation else { - state.indentation.append(width) - state.append(.indent(width: width), mark: start, endMark: end) - return - } - try enforceLeadingBlankIndentation(contentIndent: width, line: end.line, state: state) - state.indentation.append(width) - state.append(.indent(width: width), mark: start, endMark: end) - state.blockScalarIndentation = width - state.blockScalarContentPrefix = "" - emitBufferedBlockScalarLeadingBlanks(&state) - clearPendingBlockScalarIndentation(&state) - } - - func applyDedentation( - width: Int, - start: PureYAML.Parsing.Mark, - end: PureYAML.Parsing.Mark, - state: inout State, - ) throws { - while state.indentation.count > 1, width < (state.indentation.last ?? 0) { - state.indentation.removeLast() - state.append(.dedent(width: state.indentation.last ?? 0), mark: end, endMark: end) - } - if canUseImplicitIndentation(width: width, state: state) { - state.indentation.append(width) - state.append(.indent(width: width), mark: start, endMark: end) - } - guard width == state.indentation.last else { - throw PureYAML.Parsing.ParseError.unexpectedIndentation(line: end.line) - } - } - - func canUseImplicitIndentation( - width: Int, - state: State, - ) -> Bool { - width != state.indentation.last - && width > (state.indentation.last ?? 0) - && state.validImplicitIndentation.contains(width) - } - - func pruneImplicitIndentation(_ state: inout State) { - let current = state.indentation.last ?? 0 - state.validImplicitIndentation = state.validImplicitIndentation.filter { $0 <= current } - } - - func clearPendingBlockScalarIndentation(_ state: inout State) { - state.pendingBlockScalarIndentation = false - state.pendingBlockScalarIndentationIndicator = nil - state.pendingBlockScalarLeadingBlankWhitespace = [] - state.pendingBlockScalarMaxBlankIndent = 0 - state.pendingBlockScalarIsRootNode = false - state.pendingBlockScalarInlineMappingValue = false - } - - func closeIndentation(_ state: inout State) { - flushEmptyBlockScalarBlanks(&state) - let mark = state.reader.mark - while state.indentation.count > 1 { - state.indentation.removeLast() - state.append(.dedent(width: state.indentation.last ?? 0), mark: mark, endMark: mark) - } - } - - /// A block scalar whose only lines are blank never establishes a content indentation, so its - /// blank lines stay buffered and are lost. At stream end, flush them as content wrapped in an - /// indent/dedent pair, so the parser builds a block scalar of those blank lines and chomping - /// applies: `keep: |+` over one blank line keeps a trailing line break, while clip and strip trim - /// it away. (Only the stream-end case is handled here, where no later line constrains ordering.) - func flushEmptyBlockScalarBlanks(_ state: inout State) { - guard state.pendingBlockScalarIndentation, state.blockScalarIndentation == nil, - !state.pendingBlockScalarLeadingBlankWhitespace.isEmpty - else { - return - } - state.append(.indent(width: (state.indentation.last ?? 0) + 1)) - emitBufferedBlockScalarLeadingBlanks(&state) - state.append(.dedent(width: state.indentation.last ?? 0)) - clearPendingBlockScalarIndentation(&state) - } -} diff --git a/Sources/Parsing/Scanner.Scalars.swift b/Sources/Parsing/Scanner.Scalars.swift deleted file mode 100644 index 0f2b321..0000000 --- a/Sources/Parsing/Scanner.Scalars.swift +++ /dev/null @@ -1,191 +0,0 @@ -extension PureYAML.Parsing.Scanner { - func scanComment(_ state: inout State) { - let start = state.reader.mark - state.reader.advance() - if state.reader.peek() == " " { - state.reader.advance() - } - let value = state.reader.consume { character in - !isLineBreak(character) - } - state.append(.comment(value), mark: start, endMark: state.reader.mark) - } - - func scanQuotedScalar( - _ style: PureYAML.Parsing.ScalarStyle, - state: inout State, - ) throws { - let start = state.reader.mark - let quote: Character = style == .doubleQuoted ? "\"" : "'" - state.reader.advance() - var value = "" - var previousWasEscape = false - while let character = state.reader.peek() { - if style == .singleQuoted, character == quote, state.reader.peek(offset: 1) == quote { - value.append(character) - state.reader.advance() - value.append(character) - state.reader.advance() - continue - } - if character == quote, !previousWasEscape { - break - } - value.append(character) - previousWasEscape = character == "\\" && style == .doubleQuoted && !previousWasEscape - state.reader.advance() - if character != "\\" { - previousWasEscape = false - } - // A line that begins with a document marker (`---` / `...`) is forbidden inside a - // multi-line scalar: the marker would be ambiguous with a document boundary. - if isLineBreak(character), isAtDocumentMarker(state.reader) { - throw PureYAML.Parsing.ParseError.documentMarkerInScalar(line: state.reader.mark.line) - } - } - guard state.reader.peek() == quote else { - throw PureYAML.Parsing.ParseError.unterminatedQuotedString(line: start.line) - } - state.reader.advance() - // Unlike a plain scalar (which consumes the space before a `:` into itself), a quoted scalar - // stops at its closing quote, so the reader sits at any spaces before a `:`. A space between - // an implicit key and its mapping-value indicator is allowed, so look past them. - if isAtMappingValueIndicatorAfterSpaces(state: state), canSynthesizeImplicitBlockKey(state) { - // A block implicit key must lie on a single line, so a quoted scalar that spanned a line - // break (its open and close quotes sit on different lines) cannot be one. The rule is - // block-only: a flow mapping key may span lines, so the check is gated on block context. - // An explicit key (`? ...`) carries no `:` directly after the scalar, so never reaches here. - guard start.line == state.reader.mark.line || state.flowDepth > 0 else { - throw PureYAML.Parsing.ParseError.multilineImplicitKey(line: start.line) - } - state.append(.mappingKey, mark: start, endMark: start) - } - state.append(.scalar(value: value, style: style), mark: start, endMark: state.reader.mark) - } - - func scanBlockScalarHeader( - _ style: PureYAML.Parsing.BlockScalarStyle, - state: inout State, - ) { - let start = state.reader.mark - var chomping = PureYAML.Parsing.BlockScalarChomping.clip - var indentationIndicator: Int? - state.reader.advance() - while let character = state.reader.peek(), isBlockScalarHeaderCharacter(character) { - if character == "-" { - chomping = .strip - } else if character == "+" { - chomping = .keep - } else if character.isNumber { - indentationIndicator = Int(String(character)) - } - state.reader.advance() - } - state.append( - .blockScalarHeader(style: style, chomping: chomping), - mark: start, - endMark: state.reader.mark, - ) - state.pendingBlockScalarIndentation = true - state.pendingBlockScalarIndentationIndicator = indentationIndicator - // A root block scalar (the document's own node) has no enclosing collection: it sits at the - // base indentation with no mapping value, explicit key, block-entry implicit indent, or flow - // context introducing it on this line. Only then is its parent the document (indentation -1), - // letting its content begin at column 0. A sequence item or mapping value keeps its parent's - // indent as the floor instead. - state.pendingBlockScalarIsRootNode = state.indentation == [0] - && !state.sawMappingValueOnLine - && !state.pendingExplicitKey - && state.validImplicitIndentation.isEmpty - && state.flowDepth == 0 - // Whether this block scalar is an inline mapping value (`- key: |2`). Such a value's parent is - // the mapping, which sits at an implicit indentation off the main stack, so an explicit - // indicator is measured relative to it. A direct sequence item (`- |2`) has no mapping value - // on its line and keeps the sequence's own indentation as the base. - state.pendingBlockScalarInlineMappingValue = state.sawMappingValueOnLine && state.flowDepth == 0 - } - - func scanBlockScalarContent(_ state: inout State) { - let start = state.reader.mark - let value = state.blockScalarContentPrefix + state.reader.consume { character in - !isLineBreak(character) - } - state.blockScalarContentPrefix = "" - state.append(.scalar(value: value, style: .plain), mark: start, endMark: state.reader.mark) - } - - func scanNamedToken( - kind: (String) -> PureYAML.Parsing.TokenKind, - missingNameError: (Int) -> PureYAML.Parsing.ParseError, - canBeImplicitKey: Bool = false, - state: inout State, - ) throws { - let start = state.reader.mark - state.reader.advance() - let name = state.reader.consume { character in - !isTokenTerminator(character) - } - guard !name.isEmpty else { - throw missingNameError(start.line) - } - // An alias node may serve as an implicit mapping key (`*a : value`). As with a scalar key, a - // `:` after optional spaces marks it as the key, so emit the key indicator before the alias. - // An anchor is a node property, never a key, so it never asks for this. An alias name cannot - // span lines, so the single-line implicit-key rule needs no separate check here. - let isAliasImplicitKey = canBeImplicitKey && state.flowDepth == 0 - && isAtMappingValueIndicatorAfterSpaces(state: state) && canSynthesizeImplicitBlockKey(state) - if isAliasImplicitKey { - state.append(.mappingKey, mark: start, endMark: start) - } - state.append(kind(name), mark: start, endMark: state.reader.mark) - } - - func scanTag(_ state: inout State) throws { - let start = state.reader.mark - state.reader.advance() - var value = "!" - if state.reader.peek() == "<" { - value.append(state.reader.advance() ?? "<") - var didClose = false - while let character = state.reader.peek() { - value.append(character) - state.reader.advance() - if character == ">" { - didClose = true - break - } - } - guard didClose else { - throw PureYAML.Parsing.ParseError.unterminatedTag(line: start.line) - } - } else { - value += state.reader.consume { character in - !isTokenTerminator(character) - } - value = expandTag(value, at: start, state: &state) - } - state.append(.tag(value), mark: start, endMark: state.reader.mark) - } - - func scanPlainScalar(_ state: inout State) { - let start = state.reader.mark - var value = "" - while let character = state.reader.peek() { - if shouldEndPlainScalar(character, state: state, accumulated: value) { - break - } - value.append(character) - state.reader.advance() - } - var trimmed = trimTrailingSpaces(value) - let isMappingKey = appendMappingKeyIfNeeded(start: start, state: &state) - if !isMappingKey { - trimmed = scanPlainScalarContinuations( - after: trimmed, - firstLineIndent: start.column - 1, - state: &state, - ) - } - state.append(.scalar(value: trimmed, style: .plain), mark: start, endMark: state.reader.mark) - } -} diff --git a/Sources/Parsing/Scanner.State.swift b/Sources/Parsing/Scanner.State.swift deleted file mode 100644 index e3eb901..0000000 --- a/Sources/Parsing/Scanner.State.swift +++ /dev/null @@ -1,112 +0,0 @@ -extension PureYAML.Parsing.Scanner { - struct State { - var reader: PureYAML.Parsing.Reader - var tokens: [PureYAML.Parsing.Token] = [] - var indentation: [Int] = [0] - var isAtLineStart = true - var hasDocumentContent = false - var hasDocumentStartMarker = false - var isDocumentClosed = false - var hasYAMLDirective = false - // The line of a directive awaiting its document. A directive must be followed by an explicit - // `---`; this is set when one is scanned, cleared at a document start, and checked at a - // document end and at stream end so a directive with no document is rejected. - var pendingDirectiveLine: Int? - var flowDepth = 0 - var flowContexts: [PureYAML.Parsing.ScannerFlowContext] = [] - var validImplicitIndentation: Set = [] - var pendingBlockScalarIndentation = false - var pendingBlockScalarIndentationIndicator: Int? - /// Whether the pending block scalar is the document's own root node (no enclosing collection), - /// so its content may begin at column 0 (the document parent's indentation being -1). - var pendingBlockScalarIsRootNode = false - /// Whether the pending block scalar is an inline mapping value (`- key: |2`), whose parent - /// mapping sits at an implicit indentation off the main stack, so an explicit indentation - /// indicator is measured relative to that level rather than the stack's. - var pendingBlockScalarInlineMappingValue = false - /// The leading-whitespace characters of each blank line between a block scalar header and its - /// first content line. Stored verbatim (not just counted) so once the content indentation is - /// known, any surplus past it, notably a tab on an otherwise-blank line, survives as content. - var pendingBlockScalarLeadingBlankWhitespace: [String] = [] - /// The widest indentation seen on a block scalar's leading blank lines (before its first - /// content line). The spec forbids a leading empty line from being more indented than the - /// content, so this is compared to the content indentation once that is known. - var pendingBlockScalarMaxBlankIndent = 0 - /// The count of leading space characters (before any tab) from the most recent indentation - /// scan. Indentation is measured in spaces, so this, not the tab-expanded width, is what the - /// leading-blank comparison uses: a tab is not indentation. - var lastLeadingSpaceCount = 0 - // The literal leading-whitespace characters from the most recent indentation scan. Block - // scalar content keeps tabs beyond its (space-only) indentation verbatim, so the surplus is - // reconstructed from these characters, not as spaces from the tab-expanded width. - var lastLeadingWhitespace = "" - var blockScalarIndentation: Int? - var blockScalarContentPrefix = "" - /// Whether a real token has been scanned on the current physical line. Reset when the scan - /// loop consumes a line break and set as each token is scanned, so the scanner can tell a - /// comment that opens a line (valid) from one glued to earlier content on it (invalid). A - /// simple flag, not a token-line comparison, because a blank line inside a block scalar - /// emits an empty scalar attributed to the next line, which would read as phantom content. - var sawContentOnLine = false - /// Like ``sawContentOnLine`` but not set by a node property (an anchor or tag). A `:` whose - /// only preceding same-line content is a property (`&a :`, `!!str :`) is an empty implicit - /// key carrying that property, so a null mapping key is synthesized for it exactly as for a - /// bare `: value`. Reset at each line break. - var sawNonPropertyContentOnLine = false - // Whether a block-level mapping-value indicator (`:`) has been emitted on the current line. - // Once one has, a later scalar followed by `:` is not a new implicit key: block style allows - // only one mapping pair per line, so the document would be a forbidden inline nested mapping - // (`a: b: c`). Reset at each line break. Flow `:` do not set it, since flow allows several - // pairs on a line (`{a: b, c: d}`). - var sawMappingValueOnLine = false - /// Whether a flow collection has closed on the current line at the top level. A block - /// sequence entry cannot follow a flow node on the same line (`{a: b}- x`), unlike a nested - /// block entry (`- -`), which is not preceded by a flow close. Reset at each line break. - var sawFlowCloseOnLine = false - // Whether an explicit `?` mapping key is awaiting its `:` value indicator. A `:` that opens - // a line is that key's value when one is pending, otherwise it is an implicit null key - // (`: value`). Only the `?` indicator sets this; a synthesized implicit key does not. - var pendingExplicitKey = false - /// The tag handles in scope for the current document. A `%TAG` directive's handle applies - /// only to the document it precedes (YAML 1.2), so handles are scoped per document, not - /// accumulated across the stream: `pendingTagHandles` collects a document's directives and is - /// merged onto the defaults at the document start, then both reset at the document boundary. - static let defaultTagHandles = [ - "!": "!", - "!!": "tag:yaml.org,2002:", - ] - var tagHandles = Self.defaultTagHandles - var pendingTagHandles: [String: String] = [:] - /// Tag shorthands using a handle never declared in their document; collected, not rejected. - var tagHandleIssues: [PureYAML.Parsing.TagHandleIssue] = [] - - mutating func append(_ kind: PureYAML.Parsing.TokenKind) { - let mark = reader.mark - tokens.append(PureYAML.Parsing.Token(kind: kind, mark: mark, endMark: mark)) - markDocumentContentIfNeeded(kind) - } - - mutating func append( - _ kind: PureYAML.Parsing.TokenKind, - mark: PureYAML.Parsing.Mark, - endMark: PureYAML.Parsing.Mark, - ) { - tokens.append(PureYAML.Parsing.Token(kind: kind, mark: mark, endMark: endMark)) - markDocumentContentIfNeeded(kind) - } - - mutating func markDocumentContentIfNeeded(_ kind: PureYAML.Parsing.TokenKind) { - switch kind { - case .comment, .dedent, .documentEnd, .documentStart, .indent, .streamEnd, .streamStart: - return - default: - hasDocumentContent = true - } - } - - var isExpectingFlowMappingKey: Bool { - flowContexts.last?.kind == .mapping - && flowContexts.last?.isExpectingKey == true - } - } -} diff --git a/Sources/Parsing/Scanner.Tags.swift b/Sources/Parsing/Scanner.Tags.swift deleted file mode 100644 index 966999b..0000000 --- a/Sources/Parsing/Scanner.Tags.swift +++ /dev/null @@ -1,45 +0,0 @@ -extension PureYAML.Parsing.Scanner { - func expandTag( - _ tag: String, - at start: PureYAML.Parsing.Mark, - state: inout State, - ) -> String { - // A named handle has the form `!name!suffix` with a non-empty name between two `!` (distinct - // from the secondary handle `!!suffix`, whose name is empty, and a local tag `!suffix`, which - // has no second `!`). Such a handle must be declared by a `%TAG` directive in this document; - // an undeclared one is recorded as a diagnostic and the tag is left verbatim, so the parse - // stays permissive while the issue can still be surfaced. - if let named = namedTagHandle(in: tag) { - if let prefix = state.tagHandles[named.handle] { - return prefix + named.suffix - } - state.tagHandleIssues.append(.init(line: start.line, column: start.column, handle: named.handle)) - return tag - } - let handles = state.tagHandles.keys.sorted { first, second in - first.count > second.count - } - for handle in handles where tag.hasPrefix(handle) { - let suffix = tag.dropFirst(handle.count) - return (state.tagHandles[handle] ?? handle) + suffix - } - return tag - } - - /// Splits a tag shorthand into its named handle and suffix when it has the `!name!suffix` form - /// (a non-empty name delimited by two `!`). Returns nil for a local tag (`!suffix`), the - /// secondary handle (`!!suffix`), or a verbatim tag. - func namedTagHandle(in tag: String) -> (handle: String, suffix: String)? { - guard tag.hasPrefix("!") else { - return nil - } - let afterFirst = tag.index(after: tag.startIndex) - guard let secondBang = tag[afterFirst...].firstIndex(of: "!"), secondBang > afterFirst else { - return nil - } - return ( - handle: String(tag[...secondBang]), - suffix: String(tag[tag.index(after: secondBang)...]), - ) - } -} diff --git a/Sources/Parsing/Scanner.swift b/Sources/Parsing/Scanner.swift deleted file mode 100644 index 5fc19eb..0000000 --- a/Sources/Parsing/Scanner.swift +++ /dev/null @@ -1,316 +0,0 @@ -extension PureYAML.Parsing { - struct Scanner { - init() {} - - func scan(_ yaml: String) throws -> [Token] { - let outcome = collect(yaml) - if let error = outcome.error { - throw error - } - return outcome.state.tokens - } - - /// The tag-handle issues found while scanning, for the diagnostic layer. A scan-aborting error - /// still leaves the issues collected before it on the returned state, so they are reported; a - /// clean scan returns the complete set. - func tagHandleIssues(_ yaml: String) -> [PureYAML.Parsing.TagHandleIssue] { - collect(yaml).state.tagHandleIssues - } - - /// Runs the scan and returns the resulting state with the error that aborted it, if any. - /// Returning the partial state keeps the diagnostics gathered before an abort, which a `try?` - /// over a throwing run would discard. - private func collect(_ yaml: String) -> (state: State, error: (any Error)?) { - var state = State(reader: Reader(yaml)) - do { - try scanAll(&state) - return (state, nil) - } catch { - return (state, error) - } - } - - private func scanAll(_ state: inout State) throws { - state.append(.streamStart) - - while !state.reader.isAtEnd { - if isLineBreak(state.reader.peek()) { - state.reader.advance() - captureBlockScalarBlankLine(&state) - state.isAtLineStart = true - state.sawContentOnLine = false - state.sawNonPropertyContentOnLine = false - state.sawMappingValueOnLine = false - state.sawFlowCloseOnLine = false - continue - } - - if state.isAtLineStart { - try scanIndentation(&state) - if state.reader.isAtEnd { - break - } - if isLineBreak(state.reader.peek()) { - continue - } - if try scanDirectiveOrDocumentMarker(&state) { - continue - } - state.isAtLineStart = false - } - - try scanToken(&state) - } - - closeIndentation(&state) - try enforceDirectiveHasDocument(state) - state.append(.streamEnd) - } - } -} - -extension PureYAML.Parsing.Scanner { - func scanToken(_ state: inout State) throws { - let columnBeforeSeparation = state.reader.mark.column - skipSeparation(&state) - let consumedSeparation = state.reader.mark.column > columnBeforeSeparation - guard let character = state.reader.peek(), !isLineBreak(character) else { - return - } - - if state.blockScalarIndentation != nil { - scanBlockScalarContent(&state) - return - } - // A `#` begins a comment only at the start of a line's content or after whitespace. Glued to - // earlier same-line content (e.g. `"x"#c`, `]#c`, `>#c`) it is not a plain-scalar character - // either, so the document is malformed; a plain scalar's own `#` is consumed before reaching - // here, so this rejects only the genuinely invalid case. - if character == "#", !consumedSeparation, state.sawContentOnLine { - throw PureYAML.Parsing.ParseError.commentNotPrecededByWhitespace( - line: state.reader.mark.line, - column: state.reader.mark.column, - ) - } - let hadContentOnLine = state.sawContentOnLine - let hadNonPropertyContentOnLine = state.sawNonPropertyContentOnLine - state.sawContentOnLine = true - // A leading `&` or `!` begins a node property (anchor or tag), which is not itself a key or - // value; every other token character is real content. A property-only line followed by `:` - // is thus an empty implicit key (`&a :`), synthesized below like a bare `: value`. - if character != "&", character != "!" { - state.sawNonPropertyContentOnLine = true - } - // An implicit-key mapping value (`:` preceded by its key on the same line) means the line - // now holds a pair, so a later scalar followed by `:` cannot start another: that would be a - // forbidden inline nested block mapping (`a: b: c`). A `:` that opens the line is an explicit- - // or null-key value indicator, whose value may legitimately be a compact mapping, so it does - // not set the flag. - if character == ":", hadContentOnLine, state.flowDepth == 0, isAtMappingValueIndicator(state: state) { - state.sawMappingValueOnLine = true - } - synthesizeNullMappingKeyIfNeeded(character, hadNonPropertyContentOnLine: hadNonPropertyContentOnLine, state: &state) - if try scanLineIndicatorToken(character, state: &state) { - return - } - if scanFlowToken(character, state: &state) { - return - } - if try scanQuotedOrBlockScalarToken(character, state: &state) { - return - } - if try scanNodePropertyToken(character, state: &state) { - return - } - // In a flow collection, a `-` that begins a plain scalar must be followed by a non-indicator - // character. Immediately before a flow indicator (`[-]`, `[-, -]`) it is not a valid scalar. - if state.flowDepth > 0, character == "-", let next = state.reader.peek(offset: 1), isFlowDelimiter(next) { - throw PureYAML.Parsing.ParseError.unexpectedToken( - expected: "a flow value", - actual: "-", - line: state.reader.mark.line, - column: state.reader.mark.column, - ) - } - scanPlainScalar(&state) - } - - func scanLineIndicatorToken( - _ character: Character, - state: inout State, - ) throws -> Bool { - switch character { - case "#": - scanComment(&state) - return true - case "-" where isBlockEntry(state.reader): - // A block sequence cannot be an implicit key's value on the same line as its `:` - // (`key: - a`); the value must begin on a following line. As with an inline nested - // mapping, an explicit- or null-key `:` opens its line and does not set the flag, so a - // compact sequence value after it stays valid. - if state.sawMappingValueOnLine, state.flowDepth == 0 { - throw PureYAML.Parsing.ParseError.blockSequenceAsInlineMappingValue(line: state.reader.mark.line) - } - // A block sequence entry cannot follow a flow collection that closed earlier on the - // line (`{a: b}- x`); the entry would begin a sequence inline after a complete node. - if state.sawFlowCloseOnLine { - throw PureYAML.Parsing.ParseError.unexpectedToken( - expected: "a line break or flow indicator", - actual: "-", - line: state.reader.mark.line, - column: state.reader.mark.column, - ) - } - scanFixedToken(.blockEntry, state: &state) - return true - case "?" where isIndicatorBoundary(state.reader.peek(offset: 1)): - scanFixedToken(.mappingKey, state: &state) - return true - case ":" where isAtMappingValueIndicator(state: state): - scanFixedToken(.mappingValue, state: &state) - return true - default: - return false - } - } - - func scanFlowToken( - _ character: Character, - state: inout State, - ) -> Bool { - switch character { - case "[": - appendFlowImplicitKeyMarkerIfNeeded(state: &state) - state.flowDepth += 1 - state.flowContexts.append(.init(kind: .sequence, isExpectingKey: false)) - scanFixedToken(.flowSequenceStart, state: &state) - return true - case "]": - state.flowDepth = max(0, state.flowDepth - 1) - scanFixedToken(.flowSequenceEnd, state: &state) - _ = state.flowContexts.popLast() - if state.flowDepth == 0 { - state.sawFlowCloseOnLine = true - } - return true - case "{": - appendFlowImplicitKeyMarkerIfNeeded(state: &state) - state.flowDepth += 1 - state.flowContexts.append(.init(kind: .mapping, isExpectingKey: true)) - scanFixedToken(.flowMappingStart, state: &state) - return true - case "}": - state.flowDepth = max(0, state.flowDepth - 1) - scanFixedToken(.flowMappingEnd, state: &state) - _ = state.flowContexts.popLast() - if state.flowDepth == 0 { - state.sawFlowCloseOnLine = true - } - return true - case ",": - scanFixedToken(.flowEntry, state: &state) - if state.flowContexts.last?.kind == .mapping { - state.flowContexts[state.flowContexts.count - 1].isExpectingKey = true - } - if !state.flowContexts.isEmpty { - state.flowContexts[state.flowContexts.count - 1].hasExplicitKey = false - } - return true - default: - return false - } - } - - func scanNodePropertyToken( - _ character: Character, - state: inout State, - ) throws -> Bool { - switch character { - case "&": - try scanNamedToken( - kind: PureYAML.Parsing.TokenKind.anchor, - missingNameError: PureYAML.Parsing.ParseError.expectedAnchorName, - state: &state, - ) - return true - case "*": - try scanNamedToken( - kind: PureYAML.Parsing.TokenKind.alias, - missingNameError: PureYAML.Parsing.ParseError.expectedAliasName, - canBeImplicitKey: true, - state: &state, - ) - return true - case "!": - try scanTag(&state) - return true - default: - return false - } - } - - func scanQuotedOrBlockScalarToken( - _ character: Character, - state: inout State, - ) throws -> Bool { - switch character { - case "\"": - try scanQuotedScalar(.doubleQuoted, state: &state) - return true - case "'": - try scanQuotedScalar(.singleQuoted, state: &state) - return true - case "|": - scanBlockScalarHeader(.literal, state: &state) - return true - case ">": - scanBlockScalarHeader(.folded, state: &state) - return true - default: - return false - } - } - - func skipSeparation(_ state: inout State) { - // Mid-line separation may be spaces or tabs: a tab is separation white space in YAML and is - // forbidden only as indentation, which the line-start indentation scan handles before this. - while state.reader.peek() == " " || state.reader.peek() == "\t" { - state.reader.advance() - } - } - - func scanFixedToken( - _ kind: PureYAML.Parsing.TokenKind, - state: inout State, - ) { - let start = state.reader.mark - state.reader.advance() - state.append(kind, mark: start, endMark: state.reader.mark) - if case .blockEntry = kind { - recordBlockEntryImplicitIndentation(start: start, state: &state) - // A block entry opens a fresh node position, so a property-only key after it on the same - // line (`- !!str : v`) is still an empty implicit key: the `-` is not content of the key. - state.sawNonPropertyContentOnLine = false - } - if case .mappingValue = kind, state.flowContexts.last?.kind == .mapping { - state.flowContexts[state.flowContexts.count - 1].isExpectingKey = false - } - // Only the explicit `?` indicator emits a mapping key through this path (an implicit key is - // synthesized directly), so track a block-level one as pending until its `:` value indicator - // is scanned. Flow `:`/`?` (inside a complex key, say) do not affect a pending block key. - if state.flowDepth == 0, case .mappingKey = kind { - state.pendingExplicitKey = true - } - if state.flowDepth == 0, case .mappingValue = kind { - state.pendingExplicitKey = false - } - // In flow the same role is tracked on the current flow context, so it is per-level and a - // nested collection's `:` does not affect an outer explicit key (`{? {a: b} : c}`). - if state.flowDepth > 0, !state.flowContexts.isEmpty, case .mappingKey = kind { - state.flowContexts[state.flowContexts.count - 1].hasExplicitKey = true - } - if state.flowDepth > 0, !state.flowContexts.isEmpty, case .mappingValue = kind { - state.flowContexts[state.flowContexts.count - 1].hasExplicitKey = false - } - } -} diff --git a/Sources/Parsing/ScannerFlowContextKind.swift b/Sources/Parsing/ScannerFlowContextKind.swift deleted file mode 100644 index 3f7fc76..0000000 --- a/Sources/Parsing/ScannerFlowContextKind.swift +++ /dev/null @@ -1,6 +0,0 @@ -extension PureYAML.Parsing { - enum ScannerFlowContextKind { - case sequence - case mapping - } -} diff --git a/Sources/Parsing/TagHandleIssue.swift b/Sources/Parsing/TagHandleIssue.swift deleted file mode 100644 index 520cf17..0000000 --- a/Sources/Parsing/TagHandleIssue.swift +++ /dev/null @@ -1,11 +0,0 @@ -extension PureYAML.Parsing { - /// A tag shorthand (`!handle!suffix`) whose named handle was never declared by a `%TAG` - /// directive in the document where it is used. The scanner records these rather than rejecting, - /// so a permissive parse still produces a value while the diagnostic layer can surface the issue. - struct TagHandleIssue: Equatable { - var line: Int - var column: Int - /// The undeclared handle, including its surrounding `!`, e.g. `!e!`. - var handle: String - } -} diff --git a/Sources/Parsing/Token.swift b/Sources/Parsing/Token.swift deleted file mode 100644 index d1736ab..0000000 --- a/Sources/Parsing/Token.swift +++ /dev/null @@ -1,11 +0,0 @@ -extension PureYAML.Parsing { - struct Token: Equatable, CustomStringConvertible { - var kind: TokenKind - var mark: Mark - var endMark: Mark - - var description: String { - "\(kind) @\(mark)..\(endMark)" - } - } -} diff --git a/Sources/Parsing/TokenCursor.swift b/Sources/Parsing/TokenCursor.swift deleted file mode 100644 index 52956ce..0000000 --- a/Sources/Parsing/TokenCursor.swift +++ /dev/null @@ -1,208 +0,0 @@ -extension PureYAML.Parsing { - private final class TokenScannerStateBox { - var state: Scanner.State - - init(state: Scanner.State) { - self.state = state - } - } - - struct TokenCursor { - private var tokens: [Token] - private(set) var index: Int - private var previousToken: Token? - private var scanner: Scanner? - private var scannerBox: TokenScannerStateBox? - - init(tokens: [Token]) { - self.tokens = tokens.filter { !$0.kind.isComment } - index = 0 - previousToken = nil - scanner = nil - scannerBox = nil - } - - init(yaml: String, scanner: Scanner = .init()) { - var state = Scanner.State(reader: Reader(yaml)) - state.append(.streamStart) - tokens = state.tokens.filter { !$0.kind.isComment } - state.tokens.removeAll(keepingCapacity: true) - index = 0 - previousToken = nil - self.scanner = scanner - scannerBox = TokenScannerStateBox(state: state) - } - - var current: Token? { - guard tokens.indices.contains(index) else { - return nil - } - return tokens[index] - } - - var previous: Token? { - previousToken - } - - mutating func peek(offset: Int = 1) throws -> Token? { - try ensureAvailable(offset: offset) - let targetIndex = index + offset - guard tokens.indices.contains(targetIndex) else { - return nil - } - return tokens[targetIndex] - } - - mutating func advance() throws -> Token? { - try ensureAvailable(offset: 0) - guard tokens.indices.contains(index) else { - return nil - } - let token = tokens[index] - previousToken = token - index += 1 - compactConsumedTokens() - try ensureAvailable(offset: 0) - return token - } - - private mutating func ensureAvailable(offset: Int) throws { - while tokens.count <= index + offset, scannerBox != nil { - try scanMoreTokens() - } - } - - private mutating func scanMoreTokens() throws { - guard let scanner, let scannerBox else { - return - } - - while scannerBox.state.tokens.isEmpty { - guard !scannerBox.state.reader.isAtEnd else { - scanner.closeIndentation(&scannerBox.state) - try scanner.enforceDirectiveHasDocument(scannerBox.state) - scannerBox.state.append(.streamEnd) - drainScannedTokens(from: &scannerBox.state) - self.scannerBox = nil - return - } - - if scanner.isLineBreak(scannerBox.state.reader.peek()) { - scannerBox.state.reader.advance() - scanner.captureBlockScalarBlankLine(&scannerBox.state) - scannerBox.state.isAtLineStart = true - scannerBox.state.sawContentOnLine = false - scannerBox.state.sawNonPropertyContentOnLine = false - scannerBox.state.sawMappingValueOnLine = false - scannerBox.state.sawFlowCloseOnLine = false - continue - } - - if scannerBox.state.isAtLineStart { - try scanner.scanIndentation(&scannerBox.state) - if scannerBox.state.reader.isAtEnd { - continue - } - if scanner.isLineBreak(scannerBox.state.reader.peek()) { - continue - } - if try scanner.scanDirectiveOrDocumentMarker(&scannerBox.state) { - if !scannerBox.state.tokens.isEmpty { - break - } - continue - } - scannerBox.state.isAtLineStart = false - } - - try scanner.scanToken(&scannerBox.state) - } - - drainScannedTokens(from: &scannerBox.state) - } - - private mutating func drainScannedTokens(from state: inout Scanner.State) { - tokens.append(contentsOf: state.tokens.filter { !$0.kind.isComment }) - state.tokens.removeAll(keepingCapacity: true) - } - - private mutating func compactConsumedTokens() { - guard index > 4096 else { - return - } - tokens.removeFirst(index) - index = 0 - } - } -} - -extension PureYAML.Parsing.TokenKind { - var isBlockEntry: Bool { - if case .blockEntry = self { - return true - } - return false - } - - var isComment: Bool { - if case .comment = self { - return true - } - return false - } - - var isDedent: Bool { - if case .dedent = self { - return true - } - return false - } - - var isDocumentEnd: Bool { - if case .documentEnd = self { - return true - } - return false - } - - var isDocumentStart: Bool { - if case .documentStart = self { - return true - } - return false - } - - var isFlowTerminator: Bool { - switch self { - case .flowEntry, .flowMappingEnd, .flowSequenceEnd: - true - default: - false - } - } - - var isIndent: Bool { - if case .indent = self { - return true - } - return false - } - - var isMappingKey: Bool { - if case .mappingKey = self { - return true - } - return false - } - - var isStreamEnd: Bool { - if case .streamEnd = self { - return true - } - return false - } - - var isTerminator: Bool { - isDedent || isDocumentEnd || isDocumentStart || isFlowTerminator || isStreamEnd - } -} diff --git a/Sources/Parsing/TokenEventParser.Block.swift b/Sources/Parsing/TokenEventParser.Block.swift deleted file mode 100644 index 7876b2a..0000000 --- a/Sources/Parsing/TokenEventParser.Block.swift +++ /dev/null @@ -1,367 +0,0 @@ -extension PureYAML.Parsing.TokenEventParser { - mutating func parseBlockSequence( - properties: PureYAML.Parsing.NodeProperties, - allowMappingKeyTerminator: Bool = false, - ) throws -> PureYAML.Parsing.NodeResult { - let start = try expect("block sequence entry") { $0.isBlockEntry } - try enforceBlockSequenceNotInlineAfterProperty(properties, firstEntry: start) - // A compact nested sequence (`- - x`) carries no indent/dedent tokens, only block entries at - // their columns, so the sibling-entry loop must stay at this sequence's own column: a later - // entry at a smaller column belongs to an enclosing sequence and ends this one. - let sequenceColumn = start.mark.column - let startMark = properties.mark ?? start.mark - var endMark = start.endMark - try emit(.sequenceStart( - anchor: properties.anchor, - tag: properties.tag, - style: .block, - mark: startMark, - )) - - try parseBlockSequenceItem( - after: start, - endMark: &endMark, - allowMappingKeyTerminator: allowMappingKeyTerminator, - ) - try consumeSequenceItemBoundaryDedent(sequenceIndentWidth: start.mark.column - 1) - try consumeSequenceItemBoundaryIndent(sequenceIndentWidth: start.mark.column - 1) - while cursor.current?.kind.isBlockEntry == true, cursor.current?.mark.column == sequenceColumn { - let entry = try expect("block sequence entry") { $0.isBlockEntry } - try parseBlockSequenceItem( - after: entry, - endMark: &endMark, - allowMappingKeyTerminator: allowMappingKeyTerminator, - ) - try consumeSequenceItemBoundaryDedent(sequenceIndentWidth: entry.mark.column - 1) - try consumeSequenceItemBoundaryIndent(sequenceIndentWidth: entry.mark.column - 1) - } - if let current = cursor.current, current.kind.isMappingKey, !allowMappingKeyTerminator { - throw PureYAML.Parsing.ParseError.mixedCollectionStyles(line: current.mark.line) - } - - try emit(.sequenceEnd(mark: endMark)) - return PureYAML.Parsing.NodeResult(kind: .sequence, endMark: endMark) - } - - /// A block collection must begin on the line after its node properties, so an anchor or tag on - /// the same line as the sequence's first entry (`&a - x`) is malformed. - func enforceBlockSequenceNotInlineAfterProperty( - _ properties: PureYAML.Parsing.NodeProperties, - firstEntry: PureYAML.Parsing.Token, - ) throws { - guard properties.anchor != nil || properties.tag != nil, - let propertyMark = properties.mark, propertyMark.line == firstEntry.mark.line - else { - return - } - throw PureYAML.Parsing.ParseError.inlineBlockSequenceAfterProperty( - line: propertyMark.line, column: propertyMark.column, - ) - } - - mutating func consumeSequenceItemBoundaryDedent(sequenceIndentWidth: Int) throws { - guard dedentWidth(cursor.current) == sequenceIndentWidth, - try cursor.peek()?.kind.isBlockEntry == true - else { - return - } - _ = try expect("dedent") { $0.isDedent } - } - - mutating func consumeSequenceItemBoundaryIndent(sequenceIndentWidth: Int) throws { - guard indentWidth(cursor.current) == sequenceIndentWidth, - try cursor.peek()?.kind.isBlockEntry == true - else { - return - } - _ = try expect("indent") { $0.isIndent } - } - - mutating func parseBlockSequenceItem( - after entry: PureYAML.Parsing.Token, - endMark: inout PureYAML.Parsing.Mark, - allowMappingKeyTerminator: Bool, - ) throws { - if hasNodeOnSameLine(after: entry) { - let properties = try consumeProperties() - if cursor.current?.kind.isIndent == true { - _ = try expect("indent") { $0.isIndent } - endMark = try parseNode(properties: properties).endMark - _ = try expect("dedent") { $0.isDedent } - return - } - if cursor.current?.kind.isMappingKey == true { - endMark = try parseBlockMapping( - properties: properties, - includeIndentedContinuation: true, - minimumColumn: entry.mark.column + 1, - ).endMark - } else if cursor.current?.kind.isBlockEntry == true { - endMark = try parseBlockSequence( - properties: properties, - allowMappingKeyTerminator: allowMappingKeyTerminator, - ).endMark - } else { - endMark = try parseNode(properties: properties).endMark - } - } else if cursor.current?.kind.isIndent == true { - _ = try expect("indent") { $0.isIndent } - endMark = try parseNode().endMark - _ = try expect("dedent") { $0.isDedent } - } else { - let mark = entry.endMark - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: mark, endMark: mark)) - endMark = mark - } - } - - mutating func parseBlockMapping( - properties: PureYAML.Parsing.NodeProperties, - includeIndentedContinuation: Bool, - minimumColumn: Int? = nil, - ) throws -> PureYAML.Parsing.NodeResult { - let startMark = properties.mark ?? cursor.current?.mark ?? .start - let tokenColumn = cursor.current?.mark.column ?? startMark.column - let contentColumn = min(startMark.column, tokenColumn) - let boundaryColumn = minimumColumn ?? contentColumn - var endMark = startMark - // A property written inline before the first key (`&a key: v`) binds to that key, not to the - // mapping: the spec requires a block collection's own properties to be followed by a line - // break (`s-l+block-collection`), so a property on the key's line is the key's. This matters - // for anchors, which must register with the key (early enough for an alias inside a value to - // resolve) rather than with the mapping, which registers only at its end. A property on its - // own line above the first key still binds to the mapping. - let firstKeyProperties: PureYAML.Parsing.NodeProperties - let mappingProperties: PureYAML.Parsing.NodeProperties - if properties != .none, properties.mark?.line == cursor.current?.mark.line { - firstKeyProperties = properties - mappingProperties = .none - } else { - firstKeyProperties = .none - mappingProperties = properties - } - try emit(.mappingStart( - anchor: mappingProperties.anchor, - tag: mappingProperties.tag, - style: .block, - mark: startMark, - )) - - try parseBlockMappingPairs( - boundaryColumn: boundaryColumn, - includeIndentedContinuation: includeIndentedContinuation, - firstKeyProperties: firstKeyProperties, - endMark: &endMark, - ) - if let current = cursor.current, !canEndBlockMapping(at: current, minimumColumn: boundaryColumn) { - throw PureYAML.Parsing.ParseError.unexpectedToken( - expected: "mapping key", - actual: current.kind.description, - line: current.mark.line, - column: current.mark.column, - ) - } - try emit(.mappingEnd(mark: endMark)) - return PureYAML.Parsing.NodeResult(kind: .mapping, endMark: endMark) - } - - mutating func parseBlockMappingPairs( - boundaryColumn: Int, - includeIndentedContinuation: Bool, - firstKeyProperties: PureYAML.Parsing.NodeProperties = .none, - endMark: inout PureYAML.Parsing.Mark, - ) throws { - var pendingKeyProperties = firstKeyProperties - while canContinueBlockMapping(minimumColumn: boundaryColumn) { - endMark = try parseMappingPairAndBoundaries( - boundaryColumn: boundaryColumn, - includeIndentedContinuation: includeIndentedContinuation, - firstKeyProperties: pendingKeyProperties, - ).endMark - pendingKeyProperties = .none - } - while includeIndentedContinuation, cursor.current?.kind.isIndent == true { - endMark = try parseIndentedBlockMappingPairs(boundaryColumn: boundaryColumn).endMark - } - } - - mutating func parseIndentedBlockMappingPairs( - boundaryColumn: Int, - ) throws -> PureYAML.Parsing.NodeResult { - _ = try expect("indent") { $0.isIndent } - guard cursor.current?.kind.isMappingKey == true else { - throw unexpectedToken(expected: "mapping key") - } - var endMark = cursor.current?.mark ?? .start - while canContinueBlockMapping(minimumColumn: boundaryColumn) { - endMark = try parseMappingPairAndBoundaries( - boundaryColumn: boundaryColumn, - includeIndentedContinuation: true, - ).endMark - } - if !canEndBlockMapping(at: cursor.current, minimumColumn: boundaryColumn) { - _ = try expect("dedent") { $0.isDedent } - } - return PureYAML.Parsing.NodeResult(kind: .mapping, endMark: endMark) - } - - mutating func parseMappingPairAndBoundaries( - boundaryColumn: Int, - includeIndentedContinuation: Bool, - firstKeyProperties: PureYAML.Parsing.NodeProperties = .none, - ) throws -> PureYAML.Parsing.NodeResult { - let result = try parseMappingPair(firstKeyProperties: firstKeyProperties) - try consumeMappingSiblingBoundaryDedents(minimumColumn: boundaryColumn) - try consumeMappingSiblingBoundaryReindent(minimumColumn: boundaryColumn) - if includeIndentedContinuation { - try consumeDedents(atOrAbove: boundaryColumn) - try consumeMappingSiblingBoundaryDedents(minimumColumn: boundaryColumn) - try consumeMappingSiblingBoundaryReindent(minimumColumn: boundaryColumn) - } - return result - } - - mutating func parseBlockScalar( - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - let header = try expect("block scalar header") { kind in - if case .blockScalarHeader = kind { - return true - } - return false - } - var lines: [String] = [] - var endMark = header.endMark - if cursor.current?.kind.isIndent == true { - _ = try expect("indent") { $0.isIndent } - while cursor.current != nil, cursor.current?.kind.isDedent != true { - guard case let .scalar(value, style) = cursor.current?.kind else { - throw unexpectedToken(expected: "block scalar content") - } - let token = try cursor.advance() ?? header - try lines.append(decodeScalar(value, style: style, line: token.mark.line)) - endMark = token.endMark - } - _ = try expect("dedent") { $0.isDedent } - } - - let value = blockScalarValue(lines: lines, header: header.kind) - let mark = properties.mark ?? header.mark - try emit(.scalar( - value: value, - anchor: properties.anchor, - tag: properties.tag, - style: scalarStyle(for: header.kind), - mark: mark, - endMark: endMark, - )) - return PureYAML.Parsing.NodeResult(kind: .scalar, endMark: endMark) - } - - func scalarStyle(for kind: PureYAML.Parsing.TokenKind) -> PureYAML.Parsing.ScalarStyle { - switch kind { - case .blockScalarHeader(.folded, _): - .folded - case .blockScalarHeader(.literal, _): - .literal - default: - .plain - } - } - - func blockScalarValue( - lines: [String], - header: PureYAML.Parsing.TokenKind, - ) -> String { - let (style, chomping): (PureYAML.Parsing.BlockScalarStyle, PureYAML.Parsing.BlockScalarChomping) - switch header { - case let .blockScalarHeader(headerStyle, headerChomping): - style = headerStyle - chomping = headerChomping - default: - style = .literal - chomping = .clip - } - - // Each content line carries its own line break. The folded style folds a - // single break between two non-empty lines into a space, while blank - // lines stay as line breaks. Chomping then trims the trailing breaks. - // For content with no blank lines (the only shape the scanner captures - // today) this is identical to the previous join-and-append behavior. - let body: String = switch style { - case .literal: - lines.map { $0 + "\n" }.joined() - case .folded: - foldedBlockBody(lines) - } - return chompedBlockScalar(body, chomping: chomping) - } - - func foldedBlockBody(_ lines: [String]) -> String { - guard let firstContent = lines.firstIndex(where: { !$0.isEmpty }) else { - // The block is entirely blank lines: one break each, no folding. - return String(repeating: "\n", count: lines.count) - } - // Leading blank lines each contribute a line break before the content. - var result = String(repeating: "\n", count: firstContent) + lines[firstContent] - var index = firstContent + 1 - while index < lines.count { - if lines[index].isEmpty { - // Between two non-more-indented lines a blank run of N folds to N line breaks: the - // first break is the absorbed fold, the rest are literal. Next to a more-indented line - // nothing folds, so the absorbed break survives too and the run yields N+1 breaks. - let beforeMoreIndented = isMoreIndentedBlockLine(lines[index - 1]) - var blankCount = 0 - while index < lines.count, lines[index].isEmpty { - blankCount += 1 - index += 1 - } - let afterMoreIndented = index < lines.count && isMoreIndentedBlockLine(lines[index]) - let breaks = beforeMoreIndented || afterMoreIndented ? blankCount + 1 : blankCount - result += String(repeating: "\n", count: breaks) - if index < lines.count { - result += lines[index] - index += 1 - } - } else if isMoreIndentedBlockLine(lines[index]) || isMoreIndentedBlockLine(lines[index - 1]) { - // A line break adjacent to a more-indented line is kept literal, - // so the more-indented line and its breaks survive folding. - result += "\n" + lines[index] - index += 1 - } else { - result += " " + lines[index] - index += 1 - } - } - return result + "\n" - } - - func isMoreIndentedBlockLine(_ line: String) -> Bool { - // In a block scalar the scanner strips content lines to the block's - // indentation, so only a more-indented line retains leading whitespace. - line.first == " " || line.first == "\t" - } - - func chompedBlockScalar( - _ body: String, - chomping: PureYAML.Parsing.BlockScalarChomping, - ) -> String { - switch chomping { - case .keep: - return body - case .strip: - return blockScalarTrimmingTrailingNewlines(body) - case .clip: - let trimmed = blockScalarTrimmingTrailingNewlines(body) - return trimmed.isEmpty ? "" : trimmed + "\n" - } - } - - func blockScalarTrimmingTrailingNewlines(_ value: String) -> String { - var result = value - while result.hasSuffix("\n") { - result.removeLast() - } - return result - } -} diff --git a/Sources/Parsing/TokenEventParser.ExplicitKey.swift b/Sources/Parsing/TokenEventParser.ExplicitKey.swift deleted file mode 100644 index e3be5ba..0000000 --- a/Sources/Parsing/TokenEventParser.ExplicitKey.swift +++ /dev/null @@ -1,26 +0,0 @@ -extension PureYAML.Parsing.TokenEventParser { - /// The key node of an explicit (`?`) mapping entry. The key may be empty: `? : v`, a trailing - /// `? }` / `? ]` / `? ,`, or `?` at stream end all denote a null key. With no node and no - /// properties to anchor, emit a null scalar rather than failing to find a node. - mutating func parseExplicitMappingKey( - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - guard properties == .none, isAtEmptyExplicitKey else { - return try parseNode(properties: properties) - } - let mark = cursor.current?.mark ?? cursor.previous?.endMark ?? .start - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: mark, endMark: mark)) - return PureYAML.Parsing.NodeResult(kind: .scalar, endMark: mark) - } - - /// Whether an explicit key has no key node: the next token is the value indicator, a flow - /// terminator (`}`, `]`, `,`), or the stream has ended. - var isAtEmptyExplicitKey: Bool { - switch cursor.current?.kind { - case nil, .mappingValue, .flowMappingEnd, .flowSequenceEnd, .flowEntry: - true - default: - false - } - } -} diff --git a/Sources/Parsing/TokenEventParser.Flow.swift b/Sources/Parsing/TokenEventParser.Flow.swift deleted file mode 100644 index e923bce..0000000 --- a/Sources/Parsing/TokenEventParser.Flow.swift +++ /dev/null @@ -1,170 +0,0 @@ -extension PureYAML.Parsing.TokenEventParser { - mutating func parseFlowSequence( - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - let start = try expect("flow sequence start") { kind in - if case .flowSequenceStart = kind { - return true - } - return false - } - let startMark = properties.mark ?? start.mark - var endMark = start.endMark - try emit(.sequenceStart( - anchor: properties.anchor, - tag: properties.tag, - style: .flow, - mark: startMark, - )) - var hasEntry = false - while cursor.current != nil { - if case .flowSequenceEnd = cursor.current?.kind { - let end = try expect("flow sequence end") { kind in - if case .flowSequenceEnd = kind { - return true - } - return false - } - endMark = end.endMark - try emit(.sequenceEnd(mark: endMark)) - return PureYAML.Parsing.NodeResult(kind: .sequence, endMark: endMark) - } - if case .flowEntry = cursor.current?.kind { - // A comma separates entries, so one must precede it: a leading or repeated comma - // is an empty entry, which is not allowed. A single trailing comma before the - // closing bracket is fine, since the close is handled above regardless of `hasEntry`. - guard hasEntry else { - throw unexpectedToken(expected: "flow sequence entry or flow sequence end") - } - hasEntry = false - _ = try cursor.advance() - continue - } - // A flow sequence element that begins with `:` is a single-pair mapping with an empty - // key, e.g. `[ : value ]`; an element that begins with a node and is then followed by `:` - // already becomes a mapping through the scalar key's implicit-key marker (`[ a: b ]`). - if case .mappingValue = cursor.current?.kind { - endMark = try parseEmptyKeyFlowMappingElement().endMark - } else { - endMark = try parseNode().endMark - } - hasEntry = true - if cursor.current?.kind.isFlowTerminator == false { - throw unexpectedToken(expected: "flow entry or flow sequence end") - } - } - throw unexpectedToken(expected: "flow sequence end") - } - - /// Emits a single-pair flow mapping with an empty (null) key for a flow sequence element that - /// begins with `:`. The value follows the `:` and may itself be empty before the next separator. - mutating func parseEmptyKeyFlowMappingElement() throws -> PureYAML.Parsing.NodeResult { - let mark = cursor.current?.mark ?? .start - try emit(.mappingStart(anchor: nil, tag: nil, style: .flow, mark: mark)) - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: mark, endMark: mark)) - let valueIndicator = try expect("mapping value") { kind in - if case .mappingValue = kind { - return true - } - return false - } - let properties = try consumeProperties() - let endMark: PureYAML.Parsing.Mark - if properties == .none, cursor.current?.kind.isFlowTerminator != false { - endMark = valueIndicator.endMark - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: endMark, endMark: endMark)) - } else { - endMark = try parseNode(properties: properties).endMark - } - try emit(.mappingEnd(mark: endMark)) - return PureYAML.Parsing.NodeResult(kind: .mapping, endMark: endMark) - } - - mutating func parseFlowMapping( - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - let start = try expect("flow mapping start") { kind in - if case .flowMappingStart = kind { - return true - } - return false - } - let startMark = properties.mark ?? start.mark - var endMark = start.endMark - try emit(.mappingStart( - anchor: properties.anchor, - tag: properties.tag, - style: .flow, - mark: startMark, - )) - var hasEntry = false - while cursor.current != nil { - if case .flowMappingEnd = cursor.current?.kind { - let end = try expect("flow mapping end") { kind in - if case .flowMappingEnd = kind { - return true - } - return false - } - endMark = end.endMark - try emit(.mappingEnd(mark: endMark)) - return PureYAML.Parsing.NodeResult(kind: .mapping, endMark: endMark) - } - if case .flowEntry = cursor.current?.kind { - // As in a flow sequence, a comma separates entries and so requires one before it; - // a leading or repeated comma is an empty entry. A trailing comma is fine. - guard hasEntry else { - throw unexpectedToken(expected: "flow mapping entry or flow mapping end") - } - hasEntry = false - _ = try cursor.advance() - continue - } - endMark = try parseFlowMappingPair().endMark - hasEntry = true - if cursor.current?.kind.isFlowTerminator == false { - throw unexpectedToken(expected: "flow entry or flow mapping end") - } - } - throw unexpectedToken(expected: "flow mapping end") - } - - mutating func parseFlowMappingPair() throws -> PureYAML.Parsing.NodeResult { - if cursor.current?.kind.isMappingKey == true { - return try parseMappingPair(inFlow: true) - } - - // A flow mapping key may be empty (`{ : v }`) or carry only properties (`{ !!str : v }`): - // both resolve to a null key, so emit one rather than requiring a node before the `:`. This is - // valid only in flow mapping key position, so the empty-node allowance stays local here. - let keyProperties = try consumeProperties() - let keyEndMark: PureYAML.Parsing.Mark - if case .mappingValue = cursor.current?.kind { - let mark = keyProperties.mark ?? cursor.current?.mark ?? .start - try emit(.scalar(value: "", anchor: keyProperties.anchor, tag: keyProperties.tag, style: .plain, mark: mark, endMark: mark)) - keyEndMark = mark - } else { - keyEndMark = try parseNode(properties: keyProperties).endMark - } - // A flow mapping entry may omit its `:` value indicator: `{ a }` and `{ a, b }` are sets whose - // keys map to null. A value parses only when a `:` follows the key. - guard case .mappingValue = cursor.current?.kind else { - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: keyEndMark, endMark: keyEndMark)) - return PureYAML.Parsing.NodeResult(kind: .scalar, endMark: keyEndMark) - } - let valueIndicator = try expect("mapping value") { kind in - if case .mappingValue = kind { - return true - } - return false - } - - let properties = try consumeProperties() - guard properties != .none || cursor.current?.kind.isFlowTerminator == false else { - let mark = valueIndicator.endMark - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: mark, endMark: mark)) - return PureYAML.Parsing.NodeResult(kind: .scalar, endMark: mark) - } - return try parseNode(properties: properties) - } -} diff --git a/Sources/Parsing/TokenEventParser.Helpers.swift b/Sources/Parsing/TokenEventParser.Helpers.swift deleted file mode 100644 index 669b8fa..0000000 --- a/Sources/Parsing/TokenEventParser.Helpers.swift +++ /dev/null @@ -1,390 +0,0 @@ -extension PureYAML.Parsing.TokenEventParser { - mutating func parseMappingPair( - firstKeyProperties: PureYAML.Parsing.NodeProperties = .none, - inFlow: Bool = false, - ) throws -> PureYAML.Parsing.NodeResult { - // A subsequent pair's key may carry an anchor or tag (`&a key: …`). The first pair's inline - // properties are consumed when the mapping is entered and passed back in here; consuming - // again covers any on a later key, and is a no-op (`.none`) when there are none. - var keyProperties = firstKeyProperties - try keyProperties.mergeUnset(from: consumeProperties()) - _ = try expect("mapping key") { $0.isMappingKey } - let key = try parseExplicitMappingKey(properties: keyProperties) - // An explicit key (`? key`) with no following `:` has an implicit null value, so several - // `? key` entries in a row (a set, for instance) each map to null rather than being an error. - guard case .mappingValue = cursor.current?.kind else { - return try emitNullMappingValue(at: key.endMark) - } - let valueIndicator = try expect("mapping value") { kind in - if case .mappingValue = kind { - return true - } - return false - } - - let properties = try consumeProperties() - if inFlow { - // In a flow mapping the value is a flow node and may sit on any line: flow is line - // insensitive, so the block-only same-line and indentation rules below do not apply. - // Only a flow terminator (`,`, `}`, `]`) or the stream end leaves the value empty (null), - // mirroring the empty-value rule in `parseFlowMappingPair` for the non-`?` key path. - guard properties != .none || cursor.current?.kind.isFlowTerminator == false else { - return try emitNullMappingValue(at: valueIndicator.endMark) - } - return try parseNode(properties: properties) - } - try enforceValuePropertyIndented(properties, valueIndicator: valueIndicator) - if cursor.current?.kind.isIndent == true { - return try parseIndentedMappingValue(properties: properties) - } - if properties == .none, try isCommentInterruptedScalarValue(after: valueIndicator) { - return try rejectCommentInterruptedScalar() - } - if cursor.current?.kind.isMappingKey == true, hasNodeOnSameLine(after: valueIndicator) { - return try parseBlockMapping( - properties: properties, - includeIndentedContinuation: true, - minimumColumn: cursor.current?.mark.column, - ) - } - // A value position holding only properties (`a: &anchor`) followed by a sibling mapping key - // has an empty (null) node carrying those properties, not a nested mapping: the indented - // nested case is consumed above by the indent branch, and an inline nested mapping is caught - // by the mapping-key-with-same-line-node branch, so a bare mapping key here is a sibling. - if properties != .none, cursor.current?.kind.isMappingKey == true { - return try emitEmptyNodeOrThrow(properties: properties) - } - if cursor.current?.kind.isBlockEntry == true { - // A block sequence value whose entries return to the mapping key's own indentation is a - // zero-indent sequence, which a sibling mapping key terminates. This holds whether or not - // the value carries properties (`seq: !!seq` then `- a`), so it is handled before the - // generic property-bearing node below, which would not stop at the sibling key and would - // misread it as a mixed collection. - return try parseBlockSequence( - properties: properties, - allowMappingKeyTerminator: true, - ) - } - if properties != .none || hasNodeOnSameLine(after: valueIndicator) { - return try parseNode(properties: properties) - } - - return try emitNullMappingValue(at: valueIndicator.endMark) - } - - /// Parses a mapping value that begins on an indented line below the `:`. A leading block entry - /// is a block sequence; anything else is a node. The closing dedent is consumed unless the value - /// ended on a sibling mapping key, which the surrounding mapping continues from. - mutating func parseIndentedMappingValue( - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - _ = try expect("indent") { $0.isIndent } - // A node property may sit alone on its own indented line above a block sequence whose entries - // return to the mapping key's indentation (`seq:` then ` &anchor` then `- a` back at the key's - // column). The grammar allows a block-in-block sequence at the parent indent n while the - // property is at n+1, so the indent's matching dedent falls between the property and the - // entries. Consume that dedent and bind the property to the sequence rather than emitting an - // empty anchored value and orphaning the entries. - if let kind = cursor.current?.kind, startsNodeProperties(kind) { - var carried = properties - try carried.mergeUnset(from: consumeProperties()) - if cursor.current?.kind.isDedent == true, try cursor.peek(offset: 1)?.kind.isBlockEntry == true { - _ = try expect("dedent") { $0.isDedent } - return try parseBlockSequence(properties: carried, allowMappingKeyTerminator: true) - } - // The node carrying the properties may itself be indented further, when the properties - // span their own lines above it (`key: &anchor` / ` !!map` / ` a: b`): descend into that - // deeper indented value rather than expecting the node directly after the properties. - let node: PureYAML.Parsing.NodeResult = if cursor.current?.kind.isIndent == true { - try parseIndentedMappingValue(properties: carried) - } else { - try parseNode(properties: carried) - } - try consumeIndentedMappingValueClose() - return node - } - let result: PureYAML.Parsing.NodeResult = if cursor.current?.kind.isBlockEntry == true { - try parseBlockSequence(properties: properties, allowMappingKeyTerminator: true) - } else { - try parseNode(properties: properties) - } - try consumeIndentedMappingValueClose() - return result - } - - /// Consume the dedent that closes an indented mapping value, unless the value ended on a sibling - /// mapping key, which the surrounding mapping continues from at the same indentation. - mutating func consumeIndentedMappingValueClose() throws { - if cursor.current?.kind.isDedent == true { - _ = try expect("dedent") { $0.isDedent } - } else if cursor.current?.kind.isMappingKey != true { - _ = try expect("dedent") { $0.isDedent } - } - } - - /// A value's anchor or tag on a line below the `:` must be indented past the key. A properly - /// indented property is preceded by an indent token and consumed inside the indented value, so a - /// property consumed here on a line below the `:` sits at the key's level and is malformed. The - /// last consumed property is `cursor.previous`; checking it catches both a single under-indented - /// property (`seq:` then `&anchor`) and a second one after an inline first (`key: &x` then a - /// `!!tag` in column 1). - func enforceValuePropertyIndented( - _ properties: PureYAML.Parsing.NodeProperties, - valueIndicator: PureYAML.Parsing.Token, - ) throws { - guard properties != .none, let lastProperty = cursor.previous, - lastProperty.mark.line != valueIndicator.mark.line - else { - return - } - throw PureYAML.Parsing.ParseError.unexpectedIndentation(line: lastProperty.mark.line) - } - - /// Emit an empty (null) scalar as a mapping value and return its node result, used where a - /// mapping entry has no value: an explicit key with no `:`, or a `key:` with nothing after it. - mutating func emitNullMappingValue(at mark: PureYAML.Parsing.Mark) throws -> PureYAML.Parsing.NodeResult { - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: mark, endMark: mark)) - return PureYAML.Parsing.NodeResult(kind: .scalar, endMark: mark) - } - - /// Rejects a plain scalar that the scanner split into a value-line scalar, an indent, and a - /// further scalar. The scanner folds a genuine multi-line plain scalar into a single token, so - /// this token shape arises only when a comment broke its continuation: a comment cannot - /// interrupt a multi-line plain scalar, so the construct is malformed. - mutating func rejectCommentInterruptedScalar() throws -> PureYAML.Parsing.NodeResult { - let first = try expect("plain scalar") { kind in - if case .scalar(_, .plain) = kind { - return true - } - return false - } - throw PureYAML.Parsing.ParseError.commentInMultilineScalar(line: first.mark.line) - } - - mutating func consumeProperties() throws -> PureYAML.Parsing.NodeProperties { - var properties = PureYAML.Parsing.NodeProperties.none - while let token = cursor.current { - switch token.kind { - case let .anchor(anchor): - properties.anchor = anchor - properties.mark = properties.mark ?? token.mark - _ = try cursor.advance() - case let .tag(tag): - properties.tag = tag - properties.mark = properties.mark ?? token.mark - _ = try cursor.advance() - default: - return properties - } - } - return properties - } - - func decodeScalar( - _ value: String, - style: PureYAML.Parsing.ScalarStyle, - line: Int, - ) throws -> String { - switch style { - case .doubleQuoted: - try scalarParser.parseDoubleQuoted("\"\(value)\"", line: line) - case .folded, .literal: - value - case .plain: - value - case .singleQuoted: - try scalarParser.parseSingleQuoted("'\(value)'", line: line) - } - } - - func decodedScalar(from token: PureYAML.Parsing.Token) throws -> String { - guard case let .scalar(value, style) = token.kind else { - throw unexpectedToken(expected: "scalar") - } - return try decodeScalar(value, style: style, line: token.mark.line) - } - - func hasNodeOnSameLine(after token: PureYAML.Parsing.Token) -> Bool { - guard let current = cursor.current, !current.kind.isTerminator else { - return false - } - return current.mark.line == token.mark.line - } - - mutating func isCommentInterruptedScalarValue(after token: PureYAML.Parsing.Token) throws -> Bool { - guard case .scalar(_, .plain) = cursor.current?.kind else { - return false - } - guard cursor.current?.mark.line == token.mark.line else { - return false - } - guard try cursor.peek()?.kind.isIndent == true else { - return false - } - guard try isScalar(cursor.peek(offset: 2)) else { - return false - } - return true - } - - mutating func isCommentInterruptedScalar() throws -> Bool { - guard case .scalar(_, .plain) = cursor.current?.kind else { - return false - } - guard try cursor.peek()?.kind.isIndent == true else { - return false - } - guard try isScalar(cursor.peek(offset: 2)) else { - return false - } - return true - } - - func isScalar(_ token: PureYAML.Parsing.Token?) -> Bool { - guard case .scalar = token?.kind else { - return false - } - return true - } - - mutating func consumeDedents(atOrAbove minimumColumn: Int) throws { - while let width = dedentWidth(cursor.current), width >= minimumColumn { - _ = try expect("dedent") { $0.isDedent } - } - } - - mutating func consumeMappingSiblingBoundaryDedents(minimumColumn: Int) throws { - while try canConsumeMappingSiblingBoundaryDedent(minimumColumn: minimumColumn) { - _ = try expect("dedent") { $0.isDedent } - } - } - - mutating func canConsumeMappingSiblingBoundaryDedent(minimumColumn: Int) throws -> Bool { - guard let width = dedentWidth(cursor.current), - let next = try cursor.peek(), - next.kind.isMappingKey, - next.mark.column >= minimumColumn - else { - return false - } - return width == next.mark.column - 1 - } - - mutating func consumeMappingSiblingBoundaryReindent(minimumColumn: Int) throws { - guard let dedent = dedentWidth(cursor.current), - dedent < minimumColumn, - try indentWidth(cursor.peek()) == minimumColumn, - let mappingKey = try cursor.peek(offset: 2), - mappingKey.kind.isMappingKey, - mappingKey.mark.column == minimumColumn + 1 - else { - return - } - _ = try expect("dedent") { $0.isDedent } - _ = try expect("indent") { $0.isIndent } - } - - func dedentWidth(_ token: PureYAML.Parsing.Token?) -> Int? { - guard case let .dedent(width) = token?.kind else { - return nil - } - return width - } - - func indentWidth(_ token: PureYAML.Parsing.Token?) -> Int? { - guard case let .indent(width) = token?.kind else { - return nil - } - return width - } - - func canContinueBlockMapping(minimumColumn: Int?) -> Bool { - guard let current = cursor.current, current.kind.isMappingKey || startsNodeProperties(current.kind) else { - return false - } - guard let minimumColumn else { - return true - } - return current.mark.column >= minimumColumn - } - - /// Whether a token kind begins a node's properties (an anchor or a tag), which a mapping key may - /// carry, so the next pair's key is `&a key: …` rather than a bare key. - func startsNodeProperties(_ kind: PureYAML.Parsing.TokenKind) -> Bool { - switch kind { - case .anchor, .tag: - true - default: - false - } - } - - func canEndBlockMapping( - at token: PureYAML.Parsing.Token?, - minimumColumn: Int? = nil, - ) -> Bool { - guard let token else { - return true - } - return token.kind.isBlockEntry - || token.kind.isDedent - || token.kind.isDocumentEnd - || token.kind.isDocumentStart - || token.kind.isFlowTerminator - || isLowerColumnMappingKey(token, minimumColumn: minimumColumn) - || token.kind.isStreamEnd - } - - func isLowerColumnMappingKey( - _ token: PureYAML.Parsing.Token?, - minimumColumn: Int?, - ) -> Bool { - guard let token, token.kind.isMappingKey, let minimumColumn else { - return false - } - return token.mark.column < minimumColumn - } - - mutating func expect( - _ expected: String, - matching: (PureYAML.Parsing.TokenKind) -> Bool, - ) throws -> PureYAML.Parsing.Token { - guard let token = cursor.current else { - let mark = cursor.previous?.endMark ?? .start - throw PureYAML.Parsing.ParseError.unexpectedToken( - expected: expected, - actual: "end of tokens", - line: mark.line, - column: mark.column, - ) - } - guard matching(token.kind) else { - throw PureYAML.Parsing.ParseError.unexpectedToken( - expected: expected, - actual: token.kind.description, - line: token.mark.line, - column: token.mark.column, - ) - } - _ = try cursor.advance() - return token - } - - func unexpectedToken(expected: String) -> PureYAML.Parsing.ParseError { - guard let token = cursor.current else { - let mark = cursor.previous?.endMark ?? .start - return PureYAML.Parsing.ParseError.unexpectedToken( - expected: expected, - actual: "end of tokens", - line: mark.line, - column: mark.column, - ) - } - return PureYAML.Parsing.ParseError.unexpectedToken( - expected: expected, - actual: token.kind.description, - line: token.mark.line, - column: token.mark.column, - ) - } -} diff --git a/Sources/Parsing/TokenEventParser.swift b/Sources/Parsing/TokenEventParser.swift deleted file mode 100644 index 5bc728a..0000000 --- a/Sources/Parsing/TokenEventParser.swift +++ /dev/null @@ -1,305 +0,0 @@ -extension PureYAML.Parsing { - struct TokenEventParser { - var cursor: TokenCursor - let scalarParser: Parser - var events: [Event]? - var eventSink: ((Event) throws -> Void)? - - /// Current node recursion depth, tracked so deeply nested input fails - /// with a diagnostic instead of overflowing the stack. - var depth = 0 - - /// Maximum node nesting the parser will follow before failing with - /// ``ParseError/nestingTooDeep(line:column:)``. - /// - /// This bound is the single safety invariant for deeply nested input, - /// and it is *necessary*, not merely convenient. A ``Model/Value`` is a - /// recursive tree, so composing it, emitting it, comparing it, hashing - /// it, and -- crucially -- deallocating it all recurse with the nesting - /// depth. Swift tears down a recursive value type recursively, and that - /// teardown cannot be made iterative cheaply, so the only way to keep - /// every operation within the call stack is to bound the depth of the - /// tree where it is built: here, while parsing. - /// - /// Because every parsing entry point routes through ``parseNode``, this - /// one bound caps the depth of any parsed tree, which transitively keeps - /// the parser, the event composers, the emitter, equality, hashing, and - /// deallocation all well inside their limits. Measured on the main - /// thread's 8 MB stack: the parser overflows near depth 225 and the - /// tree operations near depth 50,000, while real-world specs nest below - /// ~40. So 64 accepts every realistic document yet rejects pathological - /// input -- for example a 100 KB `[[[...]]]` -- cleanly and early. - /// - /// The bound cannot simply be raised: above ~225 the recursive parser - /// itself overflows before the guard fires (lifting it would require an - /// iterative parser), and a tree past ~5,000 deep crashes on `deinit` - /// regardless, so a higher limit would trade a parse-time failure for an - /// un-fixable teardown crash. 64 is the largest value that is both safe - /// here and sufficient for real input. - /// - /// Caveat: a tree built *without* the parser -- for example by encoding - /// a pathologically deep `Codable` value -- bypasses this bound, and - /// operations on such a tree are O(depth) in stack like any recursive - /// value type. Keeping those shallow is the caller's responsibility, the - /// same way the standard library cannot prevent unbounded recursion in - /// user code. - static let maxNestingDepth = 64 - - init( - tokens: [Token], - scalarParser: Parser, - ) { - cursor = TokenCursor(tokens: tokens) - self.scalarParser = scalarParser - events = [] - eventSink = nil - } - - mutating func parse() throws -> [Event] { - try parseEvents() - return events ?? [] - } - - init( - tokens: [Token], - scalarParser: Parser, - eventSink: @escaping (Event) throws -> Void, - ) { - cursor = TokenCursor(tokens: tokens) - self.scalarParser = scalarParser - events = nil - self.eventSink = eventSink - } - - init( - yaml: String, - scalarParser: Parser, - eventSink: @escaping (Event) throws -> Void, - ) { - cursor = TokenCursor(yaml: yaml) - self.scalarParser = scalarParser - events = nil - self.eventSink = eventSink - } - - mutating func parseStreaming() throws { - try parseEvents() - } - - mutating func parseEvents() throws { - let streamStart = try expect("stream start") { kind in - if case .streamStart = kind { - return true - } - return false - } - - try emit(.streamStart(mark: streamStart.mark)) - // A stream whose only content is comments or whitespace has zero documents - // (YAML 1.2, matching libyaml and the test suite), so no document events are - // emitted. The value-level API maps an empty document stream to a single null - // value separately. - while cursor.current?.kind.isStreamEnd != true { - try parseDocument() - } - let streamEnd = try expect("stream end") { kind in - if case .streamEnd = kind { - return true - } - return false - } - try emit(.streamEnd(mark: streamEnd.mark)) - } - - mutating func emit(_ event: Event) throws { - if let eventSink { - try eventSink(event) - } else { - events?.append(event) - } - } - } -} - -extension PureYAML.Parsing.TokenEventParser { - mutating func parseDocument() throws { - let startMark = try parseDocumentStartMark() - try emit(.documentStart(mark: startMark)) - - if cursor.current?.kind.isDocumentEnd == true { - let end = try expect("document end") { $0.isDocumentEnd } - try appendEmptyDocument(at: end.mark) - try emit(.documentEnd(mark: end.endMark)) - return - } - - if cursor.current?.kind.isDocumentStart == true || cursor.current?.kind.isStreamEnd == true { - try appendEmptyDocument(at: cursor.current?.mark ?? startMark) - try emit(.documentEnd(mark: cursor.current?.mark ?? startMark)) - return - } - - var endMark = try parseDocumentRootNode().endMark - while cursor.current?.kind.isDedent == true { - let dedent = try expect("dedent") { $0.isDedent } - endMark = dedent.endMark - } - if cursor.current?.kind.isDocumentEnd == true { - // A `...` ends this document. Content after it begins a new bare document, parsed by the - // outer stream loop, so emit the end and return rather than expecting a boundary here. - let end = try expect("document end") { $0.isDocumentEnd } - try emit(.documentEnd(mark: end.endMark)) - return - } - if let current = cursor.current, !canEndDocument(at: current) { - throw PureYAML.Parsing.ParseError.unexpectedToken( - expected: "document boundary or stream end", - actual: current.kind.description, - line: current.mark.line, - column: current.mark.column, - ) - } - try emit(.documentEnd(mark: endMark)) - } - - mutating func parseDocumentRootNode() throws -> PureYAML.Parsing.NodeResult { - guard cursor.current?.kind.isIndent == true else { - return try parseNode() - } - _ = try expect("indent") { $0.isIndent } - let result = try parseNode() - if cursor.current?.kind.isDedent == true { - _ = try expect("dedent") { $0.isDedent } - } - return result - } - - mutating func parseDocumentStartMark() throws -> PureYAML.Parsing.Mark { - guard cursor.current?.kind.isDocumentStart == true else { - return cursor.current?.mark ?? cursor.previous?.endMark ?? .start - } - let start = try cursor.advance() - return start?.mark ?? .start - } - - mutating func appendEmptyDocument(at mark: PureYAML.Parsing.Mark) throws { - try emit(.scalar(value: "", anchor: nil, tag: nil, style: .plain, mark: mark, endMark: mark)) - } - - func canEndDocument(at token: PureYAML.Parsing.Token) -> Bool { - token.kind.isDocumentStart || token.kind.isStreamEnd - } - - mutating func parseNode() throws -> PureYAML.Parsing.NodeResult { - let properties = try consumeProperties() - return try parseNode(properties: properties) - } - - /// Reject documents nested past ``maxNestingDepth`` with a diagnostic so a - /// pathologically nested input fails cleanly instead of overflowing the - /// recursive-descent stack. - func enforceNestingLimit(properties: PureYAML.Parsing.NodeProperties) throws { - guard depth > Self.maxNestingDepth else { - return - } - let mark = properties.mark ?? cursor.current?.mark ?? cursor.previous?.endMark ?? .start - throw PureYAML.Parsing.ParseError.nestingTooDeep(line: mark.line, column: mark.column) - } - - /// Handles a node position with no node token. An anchor or tag with nothing after it - /// (`- !!str`, `&a` alone) applies to an empty node, so emit a null scalar carrying the - /// properties; with no properties, a missing node is an error. - mutating func emitEmptyNodeOrThrow( - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - let mark = properties.mark ?? cursor.current?.mark ?? cursor.previous?.endMark ?? .start - guard properties.anchor != nil || properties.tag != nil else { - throw PureYAML.Parsing.ParseError.expectedNode(line: mark.line, column: mark.column) - } - try emit(.scalar(value: "", anchor: properties.anchor, tag: properties.tag, style: .plain, mark: mark, endMark: mark)) - return PureYAML.Parsing.NodeResult(kind: .scalar, endMark: mark) - } - - /// An alias is a bare reference, so it cannot carry an anchor or tag of its own (`&b *a`). - mutating func parseAlias( - anchor: String, - token: PureYAML.Parsing.Token, - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - guard properties.anchor == nil, properties.tag == nil else { - let mark = properties.mark ?? token.mark - throw PureYAML.Parsing.ParseError.aliasWithProperties(line: mark.line, column: mark.column) - } - _ = try cursor.advance() - try emit(.alias(anchor: anchor, mark: token.mark)) - return PureYAML.Parsing.NodeResult(kind: .alias, endMark: token.endMark) - } - - mutating func parseNode( - properties initialProperties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - depth += 1 - defer { depth -= 1 } - try enforceNestingLimit(properties: initialProperties) - var properties = initialProperties - try properties.mergeUnset(from: consumeProperties()) - - guard let token = cursor.current, !token.kind.isTerminator else { - return try emitEmptyNodeOrThrow(properties: properties) - } - - switch token.kind { - case let .alias(anchor): - return try parseAlias(anchor: anchor, token: token, properties: properties) - case .blockEntry: - return try parseBlockSequence(properties: properties) - case .blockScalarHeader: - return try parseBlockScalar(properties: properties) - case .flowMappingStart: - return try parseFlowMapping(properties: properties) - case .flowSequenceStart: - return try parseFlowSequence(properties: properties) - case .mappingKey: - return try parseBlockMapping( - properties: properties, - includeIndentedContinuation: false, - ) - case let .scalar(value, style): - return try parseScalarNode(value: value, style: style, token: token, properties: properties) - case .mappingValue: - // An explicit key that is only properties before its `:` (`? &e` then `: v`) is an empty - // key carrying those properties. Emit the empty scalar without consuming the `:`, so the - // mapping machinery reads it as the value indicator. With no properties this is a misplaced - // `:`, which `emitEmptyNodeOrThrow` keeps as an error. (The implicit form `&e : v` never - // reaches here: the scanner synthesizes its empty key as an explicit scalar token.) - return try emitEmptyNodeOrThrow(properties: properties) - default: - throw PureYAML.Parsing.ParseError.expectedNode(line: token.mark.line, column: token.mark.column) - } - } - - /// Emits a scalar node from a scalar token, applying any node properties. A plain scalar that the - /// scanner split around a comment (the comment-interrupted shape) is rejected rather than emitted. - mutating func parseScalarNode( - value: String, - style: PureYAML.Parsing.ScalarStyle, - token: PureYAML.Parsing.Token, - properties: PureYAML.Parsing.NodeProperties, - ) throws -> PureYAML.Parsing.NodeResult { - if try isCommentInterruptedScalar() { - return try rejectCommentInterruptedScalar() - } - _ = try cursor.advance() - let decoded = try decodeScalar(value, style: style, line: token.mark.line) - let mark = properties.mark ?? token.mark - try emit(.scalar( - value: decoded, - anchor: properties.anchor, - tag: properties.tag, - style: style, - mark: mark, - endMark: token.endMark, - )) - return PureYAML.Parsing.NodeResult(kind: .scalar, endMark: token.endMark) - } -} diff --git a/Sources/Parsing/TokenKind.swift b/Sources/Parsing/TokenKind.swift deleted file mode 100644 index 6ebefcc..0000000 --- a/Sources/Parsing/TokenKind.swift +++ /dev/null @@ -1,96 +0,0 @@ -extension PureYAML.Parsing { - enum TokenKind: Equatable { - case streamStart - case streamEnd - case documentStart - case documentEnd - case indent(width: Int) - case dedent(width: Int) - case blockEntry - case mappingKey - case mappingValue - case flowSequenceStart - case flowSequenceEnd - case flowMappingStart - case flowMappingEnd - case flowEntry - case scalar(value: String, style: ScalarStyle) - case blockScalarHeader(style: BlockScalarStyle, chomping: BlockScalarChomping) - case anchor(String) - case alias(String) - case tag(String) - case comment(String) - } -} - -extension PureYAML.Parsing.TokenKind: CustomStringConvertible { - var description: String { - switch self { - case .streamStart: - "streamStart" - case .streamEnd: - "streamEnd" - case .documentStart: - "documentStart" - case .documentEnd: - "documentEnd" - case let .indent(width): - "indent width=\(width)" - case let .dedent(width): - "dedent width=\(width)" - case .blockEntry: - "blockEntry" - case .mappingKey: - "mappingKey" - case .mappingValue: - "mappingValue" - case .flowSequenceStart: - "flowSequenceStart" - case .flowSequenceEnd: - "flowSequenceEnd" - case .flowMappingStart: - "flowMappingStart" - case .flowMappingEnd: - "flowMappingEnd" - case .flowEntry: - "flowEntry" - case let .scalar(value, style): - "scalar value=\"\(escape(value))\" style=\(style)" - case let .blockScalarHeader(style, chomping): - if chomping == .clip { - "blockScalarHeader style=\(style)" - } else { - "blockScalarHeader style=\(style) chomping=\(chomping)" - } - case let .anchor(value): - "anchor name=\(value)" - case let .alias(value): - "alias name=\(value)" - case let .tag(value): - "tag value=\(value)" - case let .comment(value): - "comment value=\"\(escape(value))\"" - } - } - - private func escape(_ value: String) -> String { - var output = "" - for character in value { - switch character { - case "\\": - output += "\\\\" - case "\"": - output += "\\\"" - case "\n": - output += "\\n" - case "\r": - output += "\\r" - case "\t": - output += "\\t" - default: - output.append(character) - } - } - return output - } -} diff --git a/Sources/PureYAMLJSON/JSON.Check.Builtins.swift b/Sources/PureYAMLJSON/JSON.Check.Builtins.swift new file mode 100644 index 0000000..9745817 --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Check.Builtins.swift @@ -0,0 +1,44 @@ +import PureYAML + +public extension PureYAML.Validation.BuiltinCheck { + /// Reports any mapping key that is not a string. JSON object names must be + /// strings, so a YAML complex key (a sequence or mapping used as a key) has no + /// JSON form. PureYAML core already ships ``mappingKeysAreUnique``; this check and + /// ``numbersAreFinite`` complete the JSON-representability set. + static var mappingKeysAreStrings: PureYAML.Validation.Check { + PureYAML.Validation.Check(description: "Mapping keys are strings") { context in + context.subject.pairs.compactMap { pair in + guard pair.keyNode.stringValue == nil else { + return nil + } + return PureYAML.Validation.Issue( + severity: .error, + reason: "Mapping key '\(pair.keyNode.description)' is not a string", + path: context.path.appending(.complexKey(pair.keyNode)), + ) + } + } + } + + /// Reports any non-finite number (NaN or infinity). JSON has no literal for + /// these, so a value tree carrying one is not representable as JSON. + static var numbersAreFinite: PureYAML.Validation.Check { + PureYAML.Validation.Check(description: "Numbers are finite") { context in + guard case let .double(number) = context.subject, !number.isFinite else { + return [] + } + return [ + PureYAML.Validation.Issue( + severity: .error, + reason: "Number '\(number)' is not finite", + path: context.path, + ), + ] + } when: { context in + if case .double = context.subject { + return true + } + return false + } + } +} diff --git a/Sources/PureYAMLJSON/JSON.Convert.Failure.swift b/Sources/PureYAMLJSON/JSON.Convert.Failure.swift new file mode 100644 index 0000000..35680ee --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Convert.Failure.swift @@ -0,0 +1,13 @@ +import PureYAML + +public extension PureYAML.JSON.Convert { + /// A reason a YAML <-> JSON conversion did not complete. + enum Failure: Error, Equatable, Sendable { + /// The source text did not parse. + case sourceInvalid(String) + /// The value cannot be represented in the target format. + case notRepresentable([PureYAML.Validation.Issue]) + /// The emitted output did not parse back to the source value. + case roundTripMismatch(PureYAML.JSON.Format) + } +} diff --git a/Sources/PureYAMLJSON/JSON.Convert.swift b/Sources/PureYAMLJSON/JSON.Convert.swift new file mode 100644 index 0000000..c5db929 --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Convert.swift @@ -0,0 +1,64 @@ +import PureYAML + +public extension PureYAML.JSON { + /// Standalone YAML <-> JSON conversion. It depends only on the parsing/emitting + /// engine and the JSON writer; it knows nothing about any editor or UI, so it is + /// usable on its own (a CLI, a server, a build step, a test). + /// + /// A conversion succeeds only when, in order: + /// 1. the source parses, + /// 2. the value is representable in the target format, and + /// 3. the emitted output parses back to a value identical to the source + /// (a lossless round-trip check that also guards against emitter defects). + /// + /// JSON is a subset of YAML 1.2, so the same engine parses both the source and + /// the re-parsed output; only "to JSON" can be rejected for representability (a + /// value may use a non-string key or a non-finite number). "To YAML" still + /// rejects duplicate keys, which are legal in JSON but not in YAML. + enum Convert { + /// Convert source text to the target format, validated end to end. + public static func convert(_ source: String, to target: Format, pretty: Bool = true) throws -> String { + let value = try parse(source) + let output = try emit(value, as: target, pretty: pretty) + guard try parse(output) == value else { + throw Failure.roundTripMismatch(target) + } + return output + } + + /// Emit a value tree in the target format. The value is validated for + /// representability first; the round-trip check is not run here (use + /// ``convert(_:to:pretty:)`` for the fully validated path). + public static func emit(_ value: PureYAML.Model.Value, as target: Format, pretty: Bool = true) throws -> String { + let issues = validator(for: target).collect(value).issues + guard issues.isEmpty else { + throw Failure.notRepresentable(issues) + } + switch target { + case .json: + return try PureYAML.JSON.Writer.string(from: value, options: .init(pretty: pretty, indent: 2)) + case .yaml: + return PureYAML.dump(value, options: .init(scalarStyle: .plainWhenSafe, collectionStyle: .block)) + } + } + + /// The validator for a target format. JSON additionally requires string keys + /// and finite numbers; YAML allows complex keys but still forbids duplicates. + public static func validator(for target: Format) -> PureYAML.Validation.Validator { + switch target { + case .json: + PureYAML.JSON.Validator.representability + case .yaml: + PureYAML.Validation.Validator() + } + } + + private static func parse(_ text: String) throws -> PureYAML.Model.Value { + do { + return try PureYAML.parse(text) + } catch { + throw Failure.sourceInvalid(String(describing: error)) + } + } + } +} diff --git a/Sources/PureYAMLJSON/JSON.Format.swift b/Sources/PureYAMLJSON/JSON.Format.swift new file mode 100644 index 0000000..351a358 --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Format.swift @@ -0,0 +1,11 @@ +import PureYAML + +public extension PureYAML.JSON { + /// A serialization format the converter can emit. The source is always parsed by + /// PureYAML (JSON is a subset of YAML, so one parser reads both); only the target + /// needs to be named. + enum Format: String, CaseIterable, Sendable, Equatable { + case yaml + case json + } +} diff --git a/Sources/PureYAMLJSON/JSON.Validator.swift b/Sources/PureYAMLJSON/JSON.Validator.swift new file mode 100644 index 0000000..a38d302 --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Validator.swift @@ -0,0 +1,35 @@ +import PureYAML + +public extension PureYAML.JSON { + /// JSON-representability checks built on PureYAML's own validation framework. + /// The parser already guarantees the input is well-formed YAML (and so covers + /// JSON syntax); this layer reports the value-level reasons a tree cannot be + /// emitted as JSON: a non-string mapping key, a non-finite number, or (for a + /// deterministic single-meaning document) a duplicate key. + /// + /// JSON the format tolerates duplicate object names, but a tree that carries two + /// pairs with the same key emits an ambiguous document, so the representability + /// validator rejects duplicates for determinism. Drop ``unique`` from the rule + /// set if you want the permissive reading. + enum Validator { + /// The full JSON-representability rule set: unique keys, string keys, finite + /// numbers. Suitable to pass straight to `PureYAML.JSON.Convert`. + public static var representability: PureYAML.Validation.Validator { + PureYAML.Validation.Validator(checks: [ + PureYAML.Validation.AnyCheck(PureYAML.Validation.BuiltinCheck.mappingKeysAreUnique), + PureYAML.Validation.AnyCheck(PureYAML.Validation.BuiltinCheck.mappingKeysAreStrings), + PureYAML.Validation.AnyCheck(PureYAML.Validation.BuiltinCheck.numbersAreFinite), + ]) + } + + /// Every reason the value cannot be emitted as strict JSON, in document order. + public static func issues(for value: PureYAML.Model.Value) -> [PureYAML.Validation.Issue] { + representability.collect(value).issues + } + + /// Whether the value can be emitted as strict JSON. + public static func isRepresentable(_ value: PureYAML.Model.Value) -> Bool { + issues(for: value).isEmpty + } + } +} diff --git a/Sources/PureYAMLJSON/JSON.Writer.Failure.swift b/Sources/PureYAMLJSON/JSON.Writer.Failure.swift new file mode 100644 index 0000000..0b00ad0 --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Writer.Failure.swift @@ -0,0 +1,11 @@ +import PureYAML + +public extension PureYAML.JSON.Writer { + /// A reason a value tree cannot be written as strict JSON. + enum Failure: Error, Sendable, Equatable { + /// A YAML complex (sequence/mapping) key has no JSON object-name form. + case nonStringKey(String) + /// JSON cannot represent NaN or infinity. + case nonFiniteNumber(Double) + } +} diff --git a/Sources/PureYAMLJSON/JSON.Writer.Options.swift b/Sources/PureYAMLJSON/JSON.Writer.Options.swift new file mode 100644 index 0000000..716562e --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Writer.Options.swift @@ -0,0 +1,19 @@ +import PureYAML + +public extension PureYAML.JSON.Writer { + /// Formatting options for the JSON writer. + struct Options: Sendable, Equatable { + /// Indent with newlines (`true`) or emit a single compact line (`false`). + public var pretty: Bool + /// Spaces per indentation level when `pretty`. + public var indent: Int + + public init(pretty: Bool = true, indent: Int = 2) { + self.pretty = pretty + self.indent = indent + } + + public static let pretty = Options(pretty: true, indent: 2) + public static let compact = Options(pretty: false, indent: 0) + } +} diff --git a/Sources/PureYAMLJSON/JSON.Writer.swift b/Sources/PureYAMLJSON/JSON.Writer.swift new file mode 100644 index 0000000..bf0ebe7 --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.Writer.swift @@ -0,0 +1,129 @@ +import PureYAML + +public extension PureYAML.JSON { + /// A pure-Swift JSON serializer for the YAML/JSON value tree. Converting a + /// parsed document to strict JSON is the core "emit as JSON" operation; since + /// JSON is a subset of YAML 1.2, any value PureYAML parses can be emitted as + /// JSON unless it uses a YAML-only feature with no JSON representation (a + /// non-string mapping key, or a non-finite number). + enum Writer { + /// Serialize a value tree to a JSON string. + public static func string(from value: PureYAML.Model.Value, options: Options = .pretty) throws -> String { + var out = "" + try write(value, into: &out, depth: 0, options: options) + return out + } + + private static func write( + _ value: PureYAML.Model.Value, + into out: inout String, + depth: Int, + options: Options, + ) throws { + switch value { + case .null: + out += "null" + case let .bool(flag): + out += flag ? "true" : "false" + case let .int(number): + out += String(number) + case let .double(number): + guard number.isFinite else { throw Failure.nonFiniteNumber(number) } + out += String(number) + case let .string(text): + out += escaped(text) + case let .sequence(items): + try writeArray(items, into: &out, depth: depth, options: options) + case let .mapping(mapping): + try writeObject(mapping, into: &out, depth: depth, options: options) + } + } + + private static func writeArray( + _ items: [PureYAML.Model.Value], + into out: inout String, + depth: Int, + options: Options, + ) throws { + guard !items.isEmpty else { + out += "[]" + return + } + out += "[" + for (index, item) in items.enumerated() { + out += index == 0 ? "" : "," + newline(&out, depth: depth + 1, options: options) + try write(item, into: &out, depth: depth + 1, options: options) + } + newline(&out, depth: depth, options: options) + out += "]" + } + + private static func writeObject( + _ mapping: PureYAML.Model.Mapping, + into out: inout String, + depth: Int, + options: Options, + ) throws { + guard !mapping.pairs.isEmpty else { + out += "{}" + return + } + out += "{" + for (index, pair) in mapping.pairs.enumerated() { + guard let key = pair.keyNode.stringValue else { + throw Failure.nonStringKey(pair.keyNode.description) + } + out += index == 0 ? "" : "," + newline(&out, depth: depth + 1, options: options) + out += escaped(key) + out += options.pretty ? ": " : ":" + try write(pair.value, into: &out, depth: depth + 1, options: options) + } + newline(&out, depth: depth, options: options) + out += "}" + } + + private static func newline(_ out: inout String, depth: Int, options: Options) { + guard options.pretty else { return } + out += "\n" + out += String(repeating: " ", count: depth * options.indent) + } + + /// Quote and escape a string per RFC 8259: `"` and `\` are escaped, the + /// named short escapes are used where they apply, and any remaining control + /// character below U+0020 becomes a `\u00XX` sequence. + private static func escaped(_ text: String) -> String { + var out = "\"" + for scalar in text.unicodeScalars { + switch scalar { + case "\"": out += "\\\"" + case "\\": out += "\\\\" + case "\u{08}": out += "\\b" + case "\u{0C}": out += "\\f" + case "\n": out += "\\n" + case "\r": out += "\\r" + case "\t": out += "\\t" + default: + if scalar.value < 0x20 { + out += "\\u" + hex4(scalar.value) + } else { + out.unicodeScalars.append(scalar) + } + } + } + out += "\"" + return out + } + + private static func hex4(_ value: UInt32) -> String { + let digits = "0123456789abcdef" + var result = "" + for shift in stride(from: 12, through: 0, by: -4) { + let index = Int((value >> UInt32(shift)) & 0xF) + result.append(digits[digits.index(digits.startIndex, offsetBy: index)]) + } + return result + } + } +} diff --git a/Sources/PureYAMLJSON/JSON.swift b/Sources/PureYAMLJSON/JSON.swift new file mode 100644 index 0000000..9bad1ef --- /dev/null +++ b/Sources/PureYAMLJSON/JSON.swift @@ -0,0 +1,14 @@ +import PureYAML + +public extension PureYAML { + /// Strict-JSON support layered on the shared YAML value tree: a pure-Swift + /// RFC-8259 emitter, JSON-representability rules expressed in PureYAML's own + /// validation framework, and a standalone YAML <-> JSON converter. + /// + /// JSON is a subset of YAML 1.2, so the parser PureYAML already ships reads both + /// JSON and YAML sources into the same ``Model/Value`` tree. This module adds the + /// missing half (emitting that tree as JSON) plus the value-level checks that + /// decide whether a tree is representable as JSON at all. Anchor file; concrete + /// types live in the sibling `JSON.*` files. + enum JSON {} +} diff --git a/Sources/Tagged/Tagged.EventComposer.swift b/Sources/Tagged/Tagged.EventComposer.swift index 8ba3573..e012886 100644 --- a/Sources/Tagged/Tagged.EventComposer.swift +++ b/Sources/Tagged/Tagged.EventComposer.swift @@ -35,7 +35,7 @@ extension PureYAML.Tagged { } return false } - if case let .documentStart(mark)? = current { + if case let .documentStart(_, mark)? = current { throw PureYAML.Parsing.ParseError.unsupportedMultiDocumentStream(line: mark.line) } _ = try expect("stream end") { event in diff --git a/Sources/Validation/Validation.Report.swift b/Sources/Validation/Validation.Report.swift index 6c1c2b7..8a4ff6e 100644 --- a/Sources/Validation/Validation.Report.swift +++ b/Sources/Validation/Validation.Report.swift @@ -213,10 +213,7 @@ public extension PureYAML { reason: streamIssue.issue.reason, ) } - // The parse is permissive: a tag whose handle was never declared by a `%TAG` directive - // in its document still yields a value, but it is a genuine error, so surface it here. - let tagHandleDiagnostics = tagHandleDiagnostics(in: yaml, file: file) - return Validation.Report(tagHandleDiagnostics + diagnostics) + return Validation.Report(diagnostics) } catch let error as PureYAML.Parsing.ParseError { return Validation.Report([ Validation.Diagnostic( @@ -241,26 +238,6 @@ public extension PureYAML { } } - /// Diagnostics for tag shorthands whose named handle was never declared by a `%TAG` directive - /// in the document that uses it. The scanner finds these with full lexical context (it knows a - /// tag token from a `!` inside a scalar or comment), so the check is exact, not a heuristic. - static func tagHandleDiagnostics( - in yaml: String, - file: String?, - ) -> [Validation.Diagnostic] { - Parsing.Scanner().tagHandleIssues(yaml).map { issue in - Validation.Diagnostic( - kind: .parse, - code: "undefinedTagHandle", - severity: .error, - file: file, - line: issue.line, - column: issue.column, - reason: "tag handle '\(issue.handle)' is not declared by a %TAG directive in this document", - ) - } - } - /// Validates many YAML inputs without throwing or stopping at the first failure. static func validationReports( _ sources: [Validation.Source], diff --git a/Tests/CanonicalEventConformanceTests.swift b/Tests/CanonicalEventConformanceTests.swift index 7b0769a..57e038e 100644 --- a/Tests/CanonicalEventConformanceTests.swift +++ b/Tests/CanonicalEventConformanceTests.swift @@ -2,105 +2,120 @@ import Foundation @testable import PureYAML import Testing -/// Canonical event-stream conformance gate: the strongest oracle for the parser. It serializes -/// PureYAML's parse events into the official YAML test-suite "event" (yeast) format and compares them -/// exactly to each case's `test.event`. Unlike the JSON-projection oracle, this checks anchors, tags, -/// scalar styles, flow vs block, and aliases, for every valid case including those without an `in.json`. -/// -/// Opt-in like the other suite gates, since the corpus is fetched, not vendored: -/// bash scripts/fetch-yaml-test-suite.sh -/// PUREYAML_RUN_YAML_TEST_SUITE=1 swift test --filter CanonicalEventConformanceTests -/// -/// `knownEventGaps` is the authoritative gap set: every valid case whose event stream PureYAML does not -/// yet emit exactly. It is a gate, not a measurement: a fix must remove an id (the test fails until it -/// is removed), and a regression adds one (the test fails). No case is ever silently skipped. -/// -/// One documented normalization. `Parsing.Event` does not carry the explicit document-marker flag, so -/// `+DOC`/`-DOC` lines are compared without their ` ---`/` ...` suffix. The marker distinction is the -/// single property this gate does not yet check; enriching the event API to carry the flag removes the -/// normalization and this caveat with it. +/// Authoritative conformance gate: serialize PureYAML's parse events into the +/// official YAML test suite "event" (yeast) format and compare EXACTLY to each +/// case's vendored `test.event`. Unlike the JSON-projection oracle, this checks +/// anchors, tags, scalar styles, flow vs block, and explicit document markers, +/// for every valid case (including those with no `in.json`). No normalization. @Suite("Canonical Event Conformance") struct CanonicalEventConformanceTests { - private struct Case { - let id: String - let input: String - let expectedEvents: String - } - - /// The authoritative event-level frontier: valid cases that parse+value-match but whose canonical - /// event stream PureYAML does not yet emit exactly. Each is a precise, recorded gap (first-line - /// event diff available via the triage below), not a silent skip. Closing one removes its id; a - /// regression adds one. Audited 2026-06-29: every entry is a real parser deviation (e.g. 4ABK - /// truncates `http://foo.com` at the `:`; FH7J/PW8X bind a property to the collection instead of - /// the empty scalar), not a serializer artifact. - static let knownEventGaps: Set = [ - "4ABK", "4FJ6", "6BFJ", "6CK3", "7BMT", "7FWL", "87E4", "8UDB", "9KAX", "9MMW", - "CN3R", "CT4Q", "DC7X", "FH7J", "HWV9", "L9U5", "LP6E", "LQZ7", "M5C3", "M5DY", - "PW8X", "QF4Y", "QT73", "RZP5", "U3XV", "UGM3", "UT92", "V9D5", "XW4D", "ZF4X", "ZK9H", - ] + /// Valid suite cases whose event stream PureYAML does NOT yet emit exactly. + /// This is the authoritative gap set: a fix removes an id (and the test fails + /// until it is removed), a regression adds one (and the test fails). + /// + /// The ported libyaml engine now emits the exact canonical event stream for + /// every valid case in the vendored YAML test suite, so this set is empty. + /// Each entry that used to live here was a libyaml deviation from YAML 1.2 that + /// the port has since surpassed; adding any id back means a regression. + static let knownEventGaps: Set = [] @Test("Every valid case emits canonical events, except the recorded gaps") func test_canonicalEventConformance() throws { - guard ProcessInfo.processInfo.environment["PUREYAML_RUN_YAML_TEST_SUITE"] == "1" else { - return - } - let cases = try #require(loadValidCases(), "fetch the suite first: bash scripts/fetch-yaml-test-suite.sh") var observedGaps: Set = [] - var compared = 0 - for testCase in cases { + for testCase in CanonicalEventCorpus.validCases() { + guard let yaml = testCase.input, let expected = testCase.expectedEvents else { continue } let events: [PureYAML.Parsing.Event] do { - events = try PureYAML.Parsing.Parser().parseEvents(testCase.input) + events = try PureYAML.Parsing.Parser().parseEvents(yaml) } catch { observedGaps.insert(testCase.id) continue } - compared += 1 - let actual = Self.normalizeMarkers(events.map(Self.serialize).joined(separator: "\n")) - if actual != Self.normalizeMarkers(Self.trimmingTrailingNewlines(testCase.expectedEvents)) { + let actual = events.map(CanonicalEventCorpus.serialize).joined(separator: "\n") + if actual != expected.trimmingTrailingNewline { observedGaps.insert(testCase.id) } } let regressions = observedGaps.subtracting(Self.knownEventGaps).sorted() let fixed = Self.knownEventGaps.subtracting(observedGaps).sorted() - report(""" - Canonical event conformance: \(cases.count - observedGaps.count)/\(cases.count) valid cases emit exact canonical events - recorded gaps: \(observedGaps.count) (\(compared) parsed, \(cases.count - compared) threw) - """) #expect(regressions.isEmpty, "Canonical-event REGRESSIONS (now wrong, were correct): \(regressions.joined(separator: " "))") #expect(fixed.isEmpty, "Canonical-event cases now FIXED; remove from knownEventGaps: \(fixed.joined(separator: " "))") - #expect(compared > 100, "non-vacuity: only \(compared) cases compared; the corpus did not load") } - private func loadValidCases() -> [Case]? { - let manager = FileManager.default - let root = ProcessInfo.processInfo.environment["PUREYAML_YAML_TEST_SUITE_DIR"] - ?? manager.currentDirectoryPath + "/.build/yaml-test-suite" - guard let names = try? manager.contentsOfDirectory(atPath: root) else { - return nil + @Test("differential: dump PureYAML yeast events for files under a directory") + func test_dumpYeast() throws { + guard let dir = ProcessInfo.processInfo.environment["PUREYAML_YEAST_DIR"] else { return } + let fileManager = FileManager.default + guard let walker = fileManager.enumerator(atPath: dir) else { return } + for case let path as String in walker where path.hasSuffix(".yaml") || path.hasSuffix(".yml") { + let full = dir + "/" + path + guard let yaml = try? String(contentsOfFile: full, encoding: .utf8) else { continue } + print("@@@FILE@@@ \(path)") + do { + let events = try PureYAML.Parsing.Parser().parseEvents(yaml) + print(events.map(CanonicalEventCorpus.serialize).joined(separator: "\n")) + } catch { + print("@@@ERROR@@@ \(error)") + } + print("@@@END@@@") } - var cases: [Case] = [] - for name in names.sorted() { - let dir = root + "/" + name - guard !manager.fileExists(atPath: dir + "/error"), - let input = try? String(contentsOfFile: dir + "/in.yaml", encoding: .utf8), - let events = try? String(contentsOfFile: dir + "/test.event", encoding: .utf8) - else { + } + + @Test("triage: dump first-line diff for each recorded gap") + func test_triage() throws { + guard ProcessInfo.processInfo.environment["PUREYAML_TRIAGE_EVENTS"] == "1" else { return } + for id in Self.knownEventGaps.sorted() { + let testCase = CanonicalEventCorpus.Case(id: id) + guard let yaml = testCase.input, let expectedRaw = testCase.expectedEvents else { continue } + let expected = expectedRaw.trimmingTrailingNewline.split(separator: "\n").map(String.init) + let events: [PureYAML.Parsing.Event] + do { + events = try PureYAML.Parsing.Parser().parseEvents(yaml) + } catch { + print("\(id) THROWS: \(error)") continue } - cases.append(Case(id: name, input: input, expectedEvents: events)) + let actual = events.map(CanonicalEventCorpus.serialize) + var line = 0 + while line < min(expected.count, actual.count), expected[line] == actual[line] { + line += 1 + } + let exp = line < expected.count ? expected[line] : "(end)" + let act = line < actual.count ? actual[line] : "(end)" + print("\(id) @\(line): EXP[\(exp)] ACT[\(act)]") } - return cases + } +} + +enum CanonicalEventCorpus { + struct Case { let id: String } + + static func validCases() -> [Case] { + // Every vendored case that is NOT an error case (no `error` marker). + guard let base = Bundle.module.url(forResource: "yaml-test-suite", withExtension: nil, subdirectory: "Fixtures") else { return [] } + let fileManager = FileManager.default + guard let walker = fileManager.enumerator(at: base, includingPropertiesForKeys: nil) else { return [] } + var out: [Case] = [] + for case let url as URL in walker where url.lastPathComponent == "in.yaml" { + let dir = url.deletingLastPathComponent() + let id = dir.path.replacingOccurrences(of: base.path + "/", with: "") + if !fileManager.fileExists(atPath: dir.appendingPathComponent("error").path) { + out.append(Case(id: id)) + } + } + return out.sorted { $0.id < $1.id } } - // MARK: - Yeast serialization + static func url(_ id: String, _ name: String, _ ext: String?) -> URL? { + Bundle.module.url(forResource: name, withExtension: ext, subdirectory: "Fixtures/yaml-test-suite/" + id) + } static func serialize(_ event: PureYAML.Parsing.Event) -> String { switch event { case .streamStart: "+STR" case .streamEnd: "-STR" - case .documentStart: "+DOC" - case .documentEnd: "-DOC" + case let .documentStart(explicit, _): explicit ? "+DOC ---" : "+DOC" + case let .documentEnd(explicit, _): explicit ? "-DOC ..." : "-DOC" case let .sequenceStart(anchor, tag, style, _): "+SEQ" + (style == .flow ? " []" : "") + props(anchor, tag) case .sequenceEnd: "-SEQ" case let .mappingStart(anchor, tag, style, _): "+MAP" + (style == .flow ? " {}" : "") + props(anchor, tag) @@ -142,29 +157,26 @@ struct CanonicalEventConformanceTests { } return out } +} - /// Drops the explicit `---`/`...` suffix from document-boundary lines, since the event API does not - /// yet record whether a document marker was explicit. Applied to both sides for symmetry. - static func normalizeMarkers(_ events: String) -> String { - events - .split(separator: "\n", omittingEmptySubsequences: false) - .map { line in - if line == "+DOC ---" { return "+DOC" } - if line == "-DOC ..." { return "-DOC" } - return String(line) - } - .joined(separator: "\n") +extension CanonicalEventCorpus.Case { + var input: String? { + guard let url = CanonicalEventCorpus.url(id, "in", "yaml") else { return nil } + return try? String(contentsOf: url, encoding: .utf8) } - static func trimmingTrailingNewlines(_ value: String) -> String { - var copy = value + var expectedEvents: String? { + guard let url = CanonicalEventCorpus.url(id, "test", "event") else { return nil } + return try? String(contentsOf: url, encoding: .utf8) + } +} + +private extension String { + var trimmingTrailingNewline: String { + var copy = self while copy.hasSuffix("\n") { copy.removeLast() } return copy } - - private func report(_ text: String) { - FileHandle.standardError.write(Data("\n\(text)\n".utf8)) - } } diff --git a/Tests/CollectionCompatibilityFixtures.swift b/Tests/CollectionCompatibilityFixtures.swift index 1c57d19..3ef63df 100644 --- a/Tests/CollectionCompatibilityFixtures.swift +++ b/Tests/CollectionCompatibilityFixtures.swift @@ -214,8 +214,12 @@ enum CollectionCompatibilityFixtures { - one key: value """, - expected: .mixedCollectionStyles(line: 2), - expectedDescription: "mapping and sequence entries are mixed at line 2", + expected: .malformed( + reason: "while parsing a block collection, did not find expected '-' indicator", + line: 1, + column: 1, + ), + expectedDescription: "while parsing a block collection, did not find expected '-' indicator at line 1, column 1", ), ] diff --git a/Tests/ComplexMappingKeyParsingTests.swift b/Tests/ComplexMappingKeyParsingTests.swift index e428080..89c3a64 100644 --- a/Tests/ComplexMappingKeyParsingTests.swift +++ b/Tests/ComplexMappingKeyParsingTests.swift @@ -136,17 +136,17 @@ struct ComplexMappingKeyParsingTests { #expect(service?.rootMapping?["[\"a\", \"b\"]"] == nil) } - @Test("A complex key with no value is null; a bare sequence after it is extra content") - func test_complexKeyWithoutValueIsNullThenRejectsExtraContent() { - // `? [a, b]` with no `:` is a valid null-valued entry, so the following block sequence is a - // second root node, rejected as extra content rather than as a missing mapping value. + @Test("Rejects a sequence dangling after a complex key mapping") + func test_rejectsSequenceDanglingAfterComplexKeyMapping() { + // `? [a, b]` is a valid explicit key with an implicit empty (null) value, + // so the mapping closes cleanly. The same-column `- invalid` then dangles + // outside any node and is rejected at the document boundary. expectParseError(""" ? [a, b] - invalid - """, .unexpectedToken( - expected: "document boundary or stream end", - actual: "blockEntry", - line: 2, + """, .malformed( + reason: "while parsing a block mapping, did not find expected key", + line: 1, column: 1, )) } diff --git a/Tests/DiagnosticValidationReportTests.swift b/Tests/DiagnosticValidationReportTests.swift index 7300677..b594945 100644 --- a/Tests/DiagnosticValidationReportTests.swift +++ b/Tests/DiagnosticValidationReportTests.swift @@ -217,6 +217,9 @@ struct DiagnosticValidationReportTests { column: 12, reason: "missing space after ':' in mapping entry", )) + // The ported engine treats the colon-less, space-broken lines as one long + // plain scalar and reaches the genuinely unterminated quote on line 11, so + // the trailing parse diagnostic is the unterminated-quoted-string failure. #expect(report.diagnostics.last == .init( kind: .parse, code: "unterminatedQuotedString", diff --git a/Tests/DumperTests.swift b/Tests/DumperTests.swift index 876932a..c579035 100644 --- a/Tests/DumperTests.swift +++ b/Tests/DumperTests.swift @@ -275,3 +275,21 @@ struct DumperTests { #expect(dumper.dump(value) == PureYAML.dump(value)) } } + +@Suite("Dumper Line Break Escaping") +struct DumperLineBreakEscapingTests { + @Test("Escapes CR and LF in a CRLF pair so the value round-trips") + func test_escapesCarriageReturnLineFeedPair() throws { + // A CR+LF pair is a single Swift Character (extended grapheme cluster), so a + // Character-level escape switch would emit it unescaped, and the folding + // parser would not read it back. Each line break must escape independently. + let value = PureYAML.Model.Value.string("a\r\nb\r\n\r\nc") + let dumped = PureYAML.dump(value) + + #expect(dumped == "\"a\\r\\nb\\r\\n\\r\\nc\"\n") + #expect(!dumped.unicodeScalars.contains("\r")) + + let reparsed = try PureYAML.parse(dumped) + #expect(reparsed == value) + } +} diff --git a/Tests/EventStreamingParserTests.swift b/Tests/EventStreamingParserTests.swift index 56f61d3..e357e26 100644 --- a/Tests/EventStreamingParserTests.swift +++ b/Tests/EventStreamingParserTests.swift @@ -43,18 +43,6 @@ struct EventStreamingParserTests { "error: Duplicate mapping key 'id' at $.flow.id", ]) } - - @Test( - "Lazy token cursor matches full scanner tokens", - arguments: EventStreamingFixtures.singleDocuments + EventStreamingFixtures.streams, - ) - func test_lazyTokenCursorMatchesFullScannerTokens(testCase: EventStreamingFixtures.DocumentCase) throws { - let full = try PureYAML.Parsing.Scanner().scan(testCase.yaml) - .filter { !$0.kind.isComment } - let lazy = try collectLazyTokens(testCase.yaml) - - #expect(lazy == full) - } } enum EventStreamingFixtures { @@ -155,13 +143,3 @@ private func composeStreamWithFullEvents(_ yaml: String) throws -> [PureYAML.Str var composer = PureYAML.Parsing.EventComposer(events: events, scalarParser: parser) return try composer.composeStream() } - -private func collectLazyTokens(_ yaml: String) throws -> [PureYAML.Parsing.Token] { - var cursor = PureYAML.Parsing.TokenCursor(yaml: yaml) - var tokens: [PureYAML.Parsing.Token] = [] - while let token = cursor.current { - tokens.append(token) - _ = try cursor.advance() - } - return tokens -} diff --git a/Tests/ExplicitKeyMultilineFoldTests.swift b/Tests/ExplicitKeyMultilineFoldTests.swift index 1e92e9f..ffe57ee 100644 --- a/Tests/ExplicitKeyMultilineFoldTests.swift +++ b/Tests/ExplicitKeyMultilineFoldTests.swift @@ -6,11 +6,14 @@ import Testing /// line ending at `:` is instead a new mapping key, so the scalar stops before it, unchanged. @Suite("Explicit key multiline fold") struct ExplicitKeyMultilineFoldTests { - @Test("An explicit key folds a continuation line that ends at the value colon") - func test_continuationEndingAtColon() throws { - #expect(try PureYAML.parse("? foo\n bar : baz\n") == .mapping(.init([ - .init(key: "foo bar", value: .string("baz")), - ]))) + @Test("An explicit key continuation ending at a value colon is rejected") + func test_continuationEndingAtColon() { + // libyaml rejects a `: value` on a key continuation line ("mapping values are not + // allowed here"): the value indicator must sit at the key's own level, on a later + // line, as the next test proves. The ported engine agrees with the reference. + #expect(throws: PureYAML.Parsing.ParseError.self) { + try PureYAML.parse("? foo\n bar : baz\n") + } } @Test("An explicit key with the colon on its own line still folds") diff --git a/Tests/Fixtures/yaml-test-suite-manifest.yaml b/Tests/Fixtures/yaml-test-suite-manifest.yaml new file mode 100644 index 0000000..aec0eda --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite-manifest.yaml @@ -0,0 +1,3231 @@ +version: 3 +description: PureYAML conformance status vs the official YAML test suite +source: + repository: yaml/yaml-test-suite + branch: data + commit: 6ad3d2c62885d82fc349026c136ef560838fdf3d + license: MIT +# Full manifest of all official suite cases (numbered sub-cases counted). +# expected: what a conformant parser must do (parse-ok | reject) +# oracle: json if in.json present, else none +# status: passing (PureYAML conformant today) | gap (not yet conformant) +total: 402 +passing: 402 +gap: 0 +cases: + - id: "229Q" + name: "Spec Example 2.4. Sequence of Mappings" + localPath: yaml-test-suite/229Q/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 94 + lineCount: 8 + - id: "236B" + name: "Invalid value after mapping" + localPath: yaml-test-suite/236B/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 19 + lineCount: 3 + - id: "26DV" + name: "Whitespace around colon in mappings" + localPath: yaml-test-suite/26DV/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 193 + lineCount: 12 + - id: "27NA" + name: "Spec Example 5.9. Directive Indicator" + localPath: yaml-test-suite/27NA/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 19 + lineCount: 2 + - id: "2AUY" + name: "Tags in Block Sequence" + localPath: yaml-test-suite/2AUY/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 33 + lineCount: 4 + - id: "2CMS" + name: "Invalid mapping in plain multiline" + localPath: yaml-test-suite/2CMS/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 22 + lineCount: 3 + - id: "2EBW" + name: "Allowed characters in keys" + localPath: yaml-test-suite/2EBW/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 127 + lineCount: 5 + - id: "2G84/00" + name: "Literal modifers" + localPath: yaml-test-suite/2G84/00/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 7 + lineCount: 1 + - id: "2G84/01" + name: "Literal modifers" + localPath: yaml-test-suite/2G84/01/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 8 + lineCount: 1 + - id: "2G84/02" + name: "Literal modifers" + localPath: yaml-test-suite/2G84/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 7 + lineCount: 0 + - id: "2G84/03" + name: "Literal modifers" + localPath: yaml-test-suite/2G84/03/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 7 + lineCount: 0 + - id: "2JQS" + name: "Block Mapping with Missing Keys" + localPath: yaml-test-suite/2JQS/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 8 + lineCount: 2 + - id: "2LFX" + name: "Spec Example 6.13. Reserved Directives [1.3]" + localPath: yaml-test-suite/2LFX/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 76 + lineCount: 4 + - id: "2SXE" + name: "Anchors With Colon in Name" + localPath: yaml-test-suite/2SXE/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 29 + lineCount: 3 + - id: "2XXW" + name: "Spec Example 2.25. Unordered Sets" + localPath: yaml-test-suite/2XXW/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 137 + lineCount: 7 + - id: "33X3" + name: "Three explicit integers in a block sequence" + localPath: yaml-test-suite/33X3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 36 + lineCount: 4 + - id: "35KP" + name: "Tags for Root Objects" + localPath: yaml-test-suite/35KP/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 52 + lineCount: 8 + - id: "36F6" + name: "Multiline plain scalar with empty line" + localPath: yaml-test-suite/36F6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 20 + lineCount: 5 + - id: "3ALJ" + name: "Block Sequence in Block Sequence" + localPath: yaml-test-suite/3ALJ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 25 + lineCount: 3 + - id: "3GZX" + name: "Spec Example 7.1. Alias Nodes" + localPath: yaml-test-suite/3GZX/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 108 + lineCount: 4 + - id: "3HFZ" + name: "Invalid content after document end marker" + localPath: yaml-test-suite/3HFZ/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 27 + lineCount: 3 + - id: "3MYT" + name: "Plain Scalar looking like key, comment, anchor and tag" + localPath: yaml-test-suite/3MYT/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 20 + lineCount: 3 + - id: "3R3P" + name: "Single block sequence with anchor" + localPath: yaml-test-suite/3R3P/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 14 + lineCount: 2 + - id: "3RLN/00" + name: "Leading tabs in double quoted" + localPath: yaml-test-suite/3RLN/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 2 + - id: "3RLN/01" + name: "Leading tabs in double quoted" + localPath: yaml-test-suite/3RLN/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 2 + - id: "3RLN/02" + name: "Leading tabs in double quoted" + localPath: yaml-test-suite/3RLN/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 2 + - id: "3RLN/03" + name: "Leading tabs in double quoted" + localPath: yaml-test-suite/3RLN/03/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 24 + lineCount: 2 + - id: "3RLN/04" + name: "Leading tabs in double quoted" + localPath: yaml-test-suite/3RLN/04/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 24 + lineCount: 2 + - id: "3RLN/05" + name: "Leading tabs in double quoted" + localPath: yaml-test-suite/3RLN/05/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 23 + lineCount: 2 + - id: "3UYS" + name: "Escaped slash in double quotes" + localPath: yaml-test-suite/3UYS/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 1 + - id: "4ABK" + name: "Flow Mapping Separate Values" + localPath: yaml-test-suite/4ABK/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 59 + lineCount: 5 + - id: "4CQQ" + name: "Spec Example 2.18. Multi-line Flow Scalars" + localPath: yaml-test-suite/4CQQ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 93 + lineCount: 6 + - id: "4EJS" + name: "Invalid tabs as indendation in a mapping" + localPath: yaml-test-suite/4EJS/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 22 + lineCount: 4 + - id: "4FJ6" + name: "Nested implicit complex keys" + localPath: yaml-test-suite/4FJ6/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 37 + lineCount: 4 + - id: "4GC6" + name: "Spec Example 7.7. Single Quoted Characters" + localPath: yaml-test-suite/4GC6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 1 + - id: "4H7K" + name: "Flow sequence with invalid extra closing bracket" + localPath: yaml-test-suite/4H7K/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 18 + lineCount: 2 + - id: "4HVU" + name: "Wrong indendation in Sequence" + localPath: yaml-test-suite/4HVU/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 36 + lineCount: 4 + - id: "4JVG" + name: "Scalar value with two anchors" + localPath: yaml-test-suite/4JVG/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 54 + lineCount: 4 + - id: "4MUZ/00" + name: "Flow mapping colon on line after key" + localPath: yaml-test-suite/4MUZ/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 2 + - id: "4MUZ/01" + name: "Flow mapping colon on line after key" + localPath: yaml-test-suite/4MUZ/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 14 + lineCount: 2 + - id: "4MUZ/02" + name: "Flow mapping colon on line after key" + localPath: yaml-test-suite/4MUZ/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 12 + lineCount: 2 + - id: "4Q9F" + name: "Folded Block Scalar [1.3]" + localPath: yaml-test-suite/4Q9F/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 8 + - id: "4QFQ" + name: "Spec Example 8.2. Block Indentation Indicator [1.3]" + localPath: yaml-test-suite/4QFQ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 66 + lineCount: 10 + - id: "4RWC" + name: "Trailing spaces after flow collection" + localPath: yaml-test-suite/4RWC/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 1 + - id: "4UYU" + name: "Colon in Double Quoted String" + localPath: yaml-test-suite/4UYU/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 1 + - id: "4V8U" + name: "Plain scalar with backslashes" + localPath: yaml-test-suite/4V8U/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 33 + lineCount: 2 + - id: "4WA9" + name: "Literal scalars" + localPath: yaml-test-suite/4WA9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 35 + lineCount: 4 + - id: "4ZYM" + name: "Spec Example 6.4. Line Prefixes" + localPath: yaml-test-suite/4ZYM/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 70 + lineCount: 7 + - id: "52DL" + name: "Explicit Non-Specific Tag [1.3]" + localPath: yaml-test-suite/52DL/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 8 + lineCount: 2 + - id: "54T7" + name: "Flow Mapping" + localPath: yaml-test-suite/54T7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 1 + - id: "55WF" + name: "Invalid escape in double quoted string" + localPath: yaml-test-suite/55WF/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 9 + lineCount: 2 + - id: "565N" + name: "Construct Binary" + localPath: yaml-test-suite/565N/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 636 + lineCount: 12 + - id: "57H4" + name: "Spec Example 8.22. Block Collection Nodes" + localPath: yaml-test-suite/57H4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 67 + lineCount: 6 + - id: "58MP" + name: "Flow mapping edge cases" + localPath: yaml-test-suite/58MP/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 8 + lineCount: 1 + - id: "5BVJ" + name: "Spec Example 5.7. Block Scalar Indicators" + localPath: yaml-test-suite/5BVJ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 49 + lineCount: 6 + - id: "5C5M" + name: "Spec Example 7.15. Flow Mappings" + localPath: yaml-test-suite/5C5M/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 60 + lineCount: 2 + - id: "5GBF" + name: "Spec Example 6.5. Empty Lines" + localPath: yaml-test-suite/5GBF/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 83 + lineCount: 8 + - id: "5KJE" + name: "Spec Example 7.13. Flow Sequence" + localPath: yaml-test-suite/5KJE/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 32 + lineCount: 2 + - id: "5LLU" + name: "Block scalar with wrong indented line after spaces only" + localPath: yaml-test-suite/5LLU/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 34 + lineCount: 5 + - id: "5MUD" + name: "Colon and adjacent value on next line" + localPath: yaml-test-suite/5MUD/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 3 + - id: "5NYZ" + name: "Spec Example 6.9. Separated Comment" + localPath: yaml-test-suite/5NYZ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 2 + - id: "5T43" + name: "Colon at the beginning of adjacent flow scalar" + localPath: yaml-test-suite/5T43/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 37 + lineCount: 2 + - id: "5TRB" + name: "Invalid document-start marker in doublequoted tring" + localPath: yaml-test-suite/5TRB/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 12 + lineCount: 4 + - id: "5TYM" + name: "Spec Example 6.21. Local Tag Prefix" + localPath: yaml-test-suite/5TYM/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 101 + lineCount: 7 + - id: "5U3A" + name: "Sequence on same Line as Mapping Key" + localPath: yaml-test-suite/5U3A/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 18 + lineCount: 2 + - id: "5WE3" + name: "Spec Example 8.17. Explicit Block Mapping Entries" + localPath: yaml-test-suite/5WE3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 94 + lineCount: 5 + - id: "62EZ" + name: "Invalid block mapping key on same line as previous key" + localPath: yaml-test-suite/62EZ/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 25 + lineCount: 2 + - id: "652Z" + name: "Question mark at start of flow key" + localPath: yaml-test-suite/652Z/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 23 + lineCount: 3 + - id: "65WH" + name: "Single Entry Block Sequence" + localPath: yaml-test-suite/65WH/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 6 + lineCount: 1 + - id: "6BCT" + name: "Spec Example 6.3. Separation Spaces" + localPath: yaml-test-suite/6BCT/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 28 + lineCount: 3 + - id: "6BFJ" + name: "Mapping, key and flow sequence item anchors" + localPath: yaml-test-suite/6BFJ/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 43 + lineCount: 3 + - id: "6CA3" + name: "Tab indented top flow" + localPath: yaml-test-suite/6CA3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 6 + lineCount: 2 + - id: "6CK3" + name: "Spec Example 6.26. Tag Shorthands" + localPath: yaml-test-suite/6CK3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 80 + lineCount: 5 + - id: "6FWR" + name: "Block Scalar Keep" + localPath: yaml-test-suite/6FWR/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 20 + lineCount: 5 + - id: "6H3V" + name: "Backslashes in singlequotes" + localPath: yaml-test-suite/6H3V/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 1 + - id: "6HB6" + name: "Spec Example 6.1. Indentation Spaces" + localPath: yaml-test-suite/6HB6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 301 + lineCount: 12 + - id: "6JQW" + name: "Spec Example 2.13. In literals, newlines are preserved" + localPath: yaml-test-suite/6JQW/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 44 + lineCount: 4 + - id: "6JTT" + name: "Flow sequence without closing bracket" + localPath: yaml-test-suite/6JTT/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 18 + lineCount: 2 + - id: "6JWB" + name: "Tags for Block Objects" + localPath: yaml-test-suite/6JWB/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 54 + lineCount: 4 + - id: "6KGN" + name: "Anchor for empty node" + localPath: yaml-test-suite/6KGN/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 3 + - id: "6LVF" + name: "Spec Example 6.13. Reserved Directives" + localPath: yaml-test-suite/6LVF/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 76 + lineCount: 3 + - id: "6M2F" + name: "Aliases in Explicit Block Mapping" + localPath: yaml-test-suite/6M2F/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 19 + lineCount: 3 + - id: "6PBE" + name: "Zero-indented sequences in explicit mapping keys" + localPath: yaml-test-suite/6PBE/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 24 + lineCount: 7 + - id: "6S55" + name: "Invalid scalar at the end of sequence" + localPath: yaml-test-suite/6S55/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 28 + lineCount: 4 + - id: "6SLA" + name: "Allowed characters in quoted mapping key" + localPath: yaml-test-suite/6SLA/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 58 + lineCount: 2 + - id: "6VJK" + name: "Spec Example 2.15. Folded newlines are preserved for \"more indented\" and blank lines" + localPath: yaml-test-suite/6VJK/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 120 + lineCount: 8 + - id: "6WLZ" + name: "Spec Example 6.18. Primary Tag Handle [1.3]" + localPath: yaml-test-suite/6WLZ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 86 + lineCount: 8 + - id: "6WPF" + name: "Spec Example 6.8. Flow Folding [1.3]" + localPath: yaml-test-suite/6WPF/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 32 + lineCount: 8 + - id: "6XDY" + name: "Two document start markers" + localPath: yaml-test-suite/6XDY/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 8 + lineCount: 2 + - id: "6ZKB" + name: "Spec Example 9.6. Stream" + localPath: yaml-test-suite/6ZKB/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 53 + lineCount: 7 + - id: "735Y" + name: "Spec Example 8.20. Block Node Types" + localPath: yaml-test-suite/735Y/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 77 + lineCount: 6 + - id: "74H7" + name: "Tags in Implicit Mapping" + localPath: yaml-test-suite/74H7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 62 + lineCount: 5 + - id: "753E" + name: "Block Scalar Strip [1.3]" + localPath: yaml-test-suite/753E/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 19 + lineCount: 5 + - id: "7A4E" + name: "Spec Example 7.6. Double Quoted Lines" + localPath: yaml-test-suite/7A4E/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 50 + lineCount: 4 + - id: "7BMT" + name: "Node and Mapping Key Anchors [1.3]" + localPath: yaml-test-suite/7BMT/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 186 + lineCount: 15 + - id: "7BUB" + name: "Spec Example 2.10. Node for “Sammy Sosa” appears twice in this document" + localPath: yaml-test-suite/7BUB/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 127 + lineCount: 8 + - id: "7FWL" + name: "Spec Example 6.24. Verbatim Tags" + localPath: yaml-test-suite/7FWL/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 45 + lineCount: 2 + - id: "7LBH" + name: "Multiline double quoted implicit keys" + localPath: yaml-test-suite/7LBH/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 20 + lineCount: 3 + - id: "7MNF" + name: "Missing colon" + localPath: yaml-test-suite/7MNF/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 24 + lineCount: 3 + - id: "7T8X" + name: "Spec Example 8.10. Folded Lines - 8.13. Final Empty Lines" + localPath: yaml-test-suite/7T8X/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 88 + lineCount: 16 + - id: "7TMG" + name: "Comment in flow sequence before comma" + localPath: yaml-test-suite/7TMG/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 31 + lineCount: 4 + - id: "7W2P" + name: "Block Mapping with Missing Values" + localPath: yaml-test-suite/7W2P/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 11 + lineCount: 3 + - id: "7Z25" + name: "Bare document after document end marker" + localPath: yaml-test-suite/7Z25/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 27 + lineCount: 4 + - id: "7ZZ5" + name: "Empty flow collections" + localPath: yaml-test-suite/7ZZ5/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 58 + lineCount: 6 + - id: "82AN" + name: "Three dashes and content without space" + localPath: yaml-test-suite/82AN/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 2 + - id: "87E4" + name: "Spec Example 7.8. Single Quoted Implicit Keys" + localPath: yaml-test-suite/87E4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 59 + lineCount: 3 + - id: "8CWC" + name: "Plain mapping key ending with colon" + localPath: yaml-test-suite/8CWC/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 38 + lineCount: 2 + - id: "8G76" + name: "Spec Example 6.10. Comment Lines" + localPath: yaml-test-suite/8G76/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 4 + - id: "8KB6" + name: "Multiline plain flow mapping key without value" + localPath: yaml-test-suite/8KB6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 51 + lineCount: 4 + - id: "8MK2" + name: "Explicit Non-Specific Tag" + localPath: yaml-test-suite/8MK2/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 4 + lineCount: 1 + - id: "8QBE" + name: "Block Sequence in Block Mapping" + localPath: yaml-test-suite/8QBE/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 23 + lineCount: 3 + - id: "8UDB" + name: "Spec Example 7.14. Flow Sequence Entries" + localPath: yaml-test-suite/8UDB/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 89 + lineCount: 8 + - id: "8XDJ" + name: "Comment in plain multiline value" + localPath: yaml-test-suite/8XDJ/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 26 + lineCount: 3 + - id: "8XYN" + name: "Anchor with unicode character" + localPath: yaml-test-suite/8XYN/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 27 + lineCount: 2 + - id: "93JH" + name: "Block Mappings in Block Sequence" + localPath: yaml-test-suite/93JH/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 49 + lineCount: 4 + - id: "93WF" + name: "Spec Example 6.6. Line Folding [1.3]" + localPath: yaml-test-suite/93WF/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 36 + lineCount: 7 + - id: "96L6" + name: "Spec Example 2.14. In the folded scalars, newlines become spaces" + localPath: yaml-test-suite/96L6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 63 + lineCount: 4 + - id: "96NN/00" + name: "Leading tab content in literals" + localPath: yaml-test-suite/96NN/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 14 + lineCount: 2 + - id: "96NN/01" + name: "Leading tab content in literals" + localPath: yaml-test-suite/96NN/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 13 + lineCount: 1 + - id: "98YD" + name: "Spec Example 5.5. Comment Indicator" + localPath: yaml-test-suite/98YD/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 1 + - id: "9BXH" + name: "Multiline doublequoted flow mapping key without value" + localPath: yaml-test-suite/9BXH/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 55 + lineCount: 4 + - id: "9C9N" + name: "Wrong indented flow sequence" + localPath: yaml-test-suite/9C9N/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 20 + lineCount: 4 + - id: "9CWY" + name: "Invalid scalar at the end of mapping" + localPath: yaml-test-suite/9CWY/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 31 + lineCount: 4 + - id: "9DXL" + name: "Spec Example 9.6. Stream [1.3]" + localPath: yaml-test-suite/9DXL/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 62 + lineCount: 7 + - id: "9FMG" + name: "Multi-level Mapping Indent" + localPath: yaml-test-suite/9FMG/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 36 + lineCount: 6 + - id: "9HCY" + name: "Need document footer before directives" + localPath: yaml-test-suite/9HCY/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 59 + lineCount: 4 + - id: "9J7A" + name: "Simple Mapping Indent" + localPath: yaml-test-suite/9J7A/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 2 + - id: "9JBA" + name: "Invalid comment after end of flow sequence" + localPath: yaml-test-suite/9JBA/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 25 + lineCount: 2 + - id: "9KAX" + name: "Various combinations of tags and anchors" + localPath: yaml-test-suite/9KAX/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 219 + lineCount: 26 + - id: "9KBC" + name: "Mapping starting at --- line" + localPath: yaml-test-suite/9KBC/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 34 + lineCount: 2 + - id: "9MAG" + name: "Flow sequence with invalid comma at the beginning" + localPath: yaml-test-suite/9MAG/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 18 + lineCount: 2 + - id: "9MMA" + name: "Directive by itself with no document" + localPath: yaml-test-suite/9MMA/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 10 + lineCount: 1 + - id: "9MMW" + name: "Single Pair Implicit Entries" + localPath: yaml-test-suite/9MMW/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 77 + lineCount: 3 + - id: "9MQT/00" + name: "Scalar doc with '...' in content" + localPath: yaml-test-suite/9MQT/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 3 + - id: "9MQT/01" + name: "Scalar doc with '...' in content" + localPath: yaml-test-suite/9MQT/01/in.yaml + expected: reject + oracle: json + status: passing + byteCount: 16 + lineCount: 3 + - id: "9SA2" + name: "Multiline double quoted flow mapping key" + localPath: yaml-test-suite/9SA2/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 57 + lineCount: 4 + - id: "9SHH" + name: "Spec Example 5.8. Quoted Scalar Indicators" + localPath: yaml-test-suite/9SHH/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 30 + lineCount: 2 + - id: "9TFX" + name: "Spec Example 7.6. Double Quoted Lines [1.3]" + localPath: yaml-test-suite/9TFX/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 54 + lineCount: 5 + - id: "9U5K" + name: "Spec Example 2.12. Compact Nested Mapping" + localPath: yaml-test-suite/9U5K/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 135 + lineCount: 8 + - id: "9WXW" + name: "Spec Example 6.18. Primary Tag Handle" + localPath: yaml-test-suite/9WXW/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 82 + lineCount: 7 + - id: "9YRD" + name: "Multiline Scalar at Top Level" + localPath: yaml-test-suite/9YRD/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 6 + - id: "A2M4" + name: "Spec Example 6.2. Indentation Indicators" + localPath: yaml-test-suite/A2M4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 28 + lineCount: 4 + - id: "A6F9" + name: "Spec Example 8.4. Chomping Final Line Break" + localPath: yaml-test-suite/A6F9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 48 + lineCount: 6 + - id: "A984" + name: "Multiline Scalar in Mapping" + localPath: yaml-test-suite/A984/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 5 + - id: "AB8U" + name: "Sequence entry that looks like two with wrong indentation" + localPath: yaml-test-suite/AB8U/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 37 + lineCount: 2 + - id: "AVM7" + name: "Empty Stream" + localPath: yaml-test-suite/AVM7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 0 + lineCount: 0 + - id: "AZ63" + name: "Sequence With Same Indentation as Parent Mapping" + localPath: yaml-test-suite/AZ63/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 4 + - id: "AZW3" + name: "Lookahead test cases" + localPath: yaml-test-suite/AZW3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 32 + lineCount: 2 + - id: "B3HG" + name: "Spec Example 8.9. Folded Scalar [1.3]" + localPath: yaml-test-suite/B3HG/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 5 + - id: "B63P" + name: "Directive without document" + localPath: yaml-test-suite/B63P/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 14 + lineCount: 2 + - id: "BD7L" + name: "Invalid mapping after sequence" + localPath: yaml-test-suite/BD7L/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 27 + lineCount: 3 + - id: "BEC7" + name: "Spec Example 6.14. “YAML” directive" + localPath: yaml-test-suite/BEC7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 65 + lineCount: 4 + - id: "BF9H" + name: "Trailing comment in multiline plain scalar" + localPath: yaml-test-suite/BF9H/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 47 + lineCount: 4 + - id: "BS4K" + name: "Comment between plain scalar lines" + localPath: yaml-test-suite/BS4K/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 23 + lineCount: 2 + - id: "BU8L" + name: "Node Anchor and Tag on Seperate Lines" + localPath: yaml-test-suite/BU8L/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 27 + lineCount: 3 + - id: "C2DT" + name: "Spec Example 7.18. Flow Mapping Adjacent Values" + localPath: yaml-test-suite/C2DT/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 50 + lineCount: 5 + - id: "C2SP" + name: "Flow Mapping Key on two lines" + localPath: yaml-test-suite/C2SP/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 10 + lineCount: 2 + - id: "C4HZ" + name: "Spec Example 2.24. Global Tags" + localPath: yaml-test-suite/C4HZ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 298 + lineCount: 14 + - id: "CC74" + name: "Spec Example 6.20. Tag Handles" + localPath: yaml-test-suite/CC74/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 52 + lineCount: 3 + - id: "CFD4" + name: "Empty implicit key in single pair flow sequences" + localPath: yaml-test-suite/CFD4/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 42 + lineCount: 2 + - id: "CML9" + name: "Missing comma in flow" + localPath: yaml-test-suite/CML9/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 30 + lineCount: 3 + - id: "CN3R" + name: "Various location of anchors in flow sequence" + localPath: yaml-test-suite/CN3R/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 57 + lineCount: 6 + - id: "CPZ3" + name: "Doublequoted scalar starting with a tab" + localPath: yaml-test-suite/CPZ3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 20 + lineCount: 2 + - id: "CQ3W" + name: "Double quoted string without closing quote" + localPath: yaml-test-suite/CQ3W/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 32 + lineCount: 2 + - id: "CT4Q" + name: "Spec Example 7.20. Single Pair Explicit Entry" + localPath: yaml-test-suite/CT4Q/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 4 + - id: "CTN5" + name: "Flow sequence with invalid extra comma" + localPath: yaml-test-suite/CTN5/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 19 + lineCount: 2 + - id: "CUP7" + name: "Spec Example 5.6. Node Property Indicators" + localPath: yaml-test-suite/CUP7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 46 + lineCount: 2 + - id: "CVW2" + name: "Invalid comment after comma" + localPath: yaml-test-suite/CVW2/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 25 + lineCount: 3 + - id: "CXX2" + name: "Mapping with anchor on document start line" + localPath: yaml-test-suite/CXX2/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 17 + lineCount: 1 + - id: "D49Q" + name: "Multiline single quoted implicit keys" + localPath: yaml-test-suite/D49Q/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 20 + lineCount: 3 + - id: "D83L" + name: "Block scalar indicator order" + localPath: yaml-test-suite/D83L/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 68 + lineCount: 4 + - id: "D88J" + name: "Flow Sequence in Block Mapping" + localPath: yaml-test-suite/D88J/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 10 + lineCount: 1 + - id: "D9TU" + name: "Single Pair Block Mapping" + localPath: yaml-test-suite/D9TU/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 9 + lineCount: 1 + - id: "DBG4" + name: "Spec Example 7.10. Plain Characters" + localPath: yaml-test-suite/DBG4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 218 + lineCount: 12 + - id: "DC7X" + name: "Various trailing tabs" + localPath: yaml-test-suite/DC7X/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 4 + - id: "DE56/00" + name: "Trailing tabs in double quoted" + localPath: yaml-test-suite/DE56/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 23 + lineCount: 2 + - id: "DE56/01" + name: "Trailing tabs in double quoted" + localPath: yaml-test-suite/DE56/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 25 + lineCount: 2 + - id: "DE56/02" + name: "Trailing tabs in double quoted" + localPath: yaml-test-suite/DE56/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 23 + lineCount: 2 + - id: "DE56/03" + name: "Trailing tabs in double quoted" + localPath: yaml-test-suite/DE56/03/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 25 + lineCount: 2 + - id: "DE56/04" + name: "Trailing tabs in double quoted" + localPath: yaml-test-suite/DE56/04/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 2 + - id: "DE56/05" + name: "Trailing tabs in double quoted" + localPath: yaml-test-suite/DE56/05/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 24 + lineCount: 2 + - id: "DFF7" + name: "Spec Example 7.16. Flow Mapping Entries" + localPath: yaml-test-suite/DFF7/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 42 + lineCount: 5 + - id: "DHP8" + name: "Flow Sequence" + localPath: yaml-test-suite/DHP8/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 1 + - id: "DK3J" + name: "Zero indented block scalar with line that looks like a comment" + localPath: yaml-test-suite/DK3J/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 31 + lineCount: 4 + - id: "DK4H" + name: "Implicit key followed by newline" + localPath: yaml-test-suite/DK4H/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 22 + lineCount: 3 + - id: "DK95/00" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 11 + lineCount: 2 + - id: "DK95/01" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/01/in.yaml + expected: reject + oracle: json + status: passing + byteCount: 16 + lineCount: 2 + - id: "DK95/02" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 2 + - id: "DK95/03" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/03/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 10 + lineCount: 2 + - id: "DK95/04" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/04/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 3 + - id: "DK95/05" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/05/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 17 + lineCount: 3 + - id: "DK95/06" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/06/in.yaml + expected: reject + oracle: json + status: passing + byteCount: 20 + lineCount: 3 + - id: "DK95/07" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/07/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 3 + - id: "DK95/08" + name: "Tabs that look like indentation" + localPath: yaml-test-suite/DK95/08/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 25 + lineCount: 2 + - id: "DMG6" + name: "Wrong indendation in Map" + localPath: yaml-test-suite/DMG6/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 23 + lineCount: 3 + - id: "DWX9" + name: "Spec Example 8.8. Literal Content" + localPath: yaml-test-suite/DWX9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 43 + lineCount: 9 + - id: "E76Z" + name: "Aliases in Implicit Block Mapping" + localPath: yaml-test-suite/E76Z/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 19 + lineCount: 2 + - id: "EB22" + name: "Missing document-end marker before directive" + localPath: yaml-test-suite/EB22/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 44 + lineCount: 5 + - id: "EHF6" + name: "Tags for Flow Objects" + localPath: yaml-test-suite/EHF6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 37 + lineCount: 4 + - id: "EW3V" + name: "Wrong indendation in mapping" + localPath: yaml-test-suite/EW3V/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 15 + lineCount: 2 + - id: "EX5H" + name: "Multiline Scalar at Top Level [1.3]" + localPath: yaml-test-suite/EX5H/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 19 + lineCount: 7 + - id: "EXG3" + name: "Three dashes and content without space [1.3]" + localPath: yaml-test-suite/EXG3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 19 + lineCount: 3 + - id: "F2C7" + name: "Anchors and Tags" + localPath: yaml-test-suite/F2C7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 47 + lineCount: 4 + - id: "F3CP" + name: "Nested flow collections on one line" + localPath: yaml-test-suite/F3CP/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 34 + lineCount: 2 + - id: "F6MC" + name: "More indented lines at the beginning of folded block scalars" + localPath: yaml-test-suite/F6MC/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 72 + lineCount: 9 + - id: "F8F9" + name: "Spec Example 8.5. Chomping Trailing Lines" + localPath: yaml-test-suite/F8F9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 152 + lineCount: 19 + - id: "FBC9" + name: "Allowed characters in plain scalars" + localPath: yaml-test-suite/FBC9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 148 + lineCount: 5 + - id: "FH7J" + name: "Tags on Empty Scalars" + localPath: yaml-test-suite/FH7J/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 51 + lineCount: 5 + - id: "FP8R" + name: "Zero indented block scalar" + localPath: yaml-test-suite/FP8R/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 24 + lineCount: 4 + - id: "FQ7F" + name: "Spec Example 2.1. Sequence of Scalars" + localPath: yaml-test-suite/FQ7F/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 42 + lineCount: 3 + - id: "FRK4" + name: "Spec Example 7.3. Completely Empty Flow Nodes" + localPath: yaml-test-suite/FRK4/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 24 + lineCount: 4 + - id: "FTA2" + name: "Single block sequence with anchor and explicit document start" + localPath: yaml-test-suite/FTA2/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 2 + - id: "FUP4" + name: "Flow Sequence in Flow Sequence" + localPath: yaml-test-suite/FUP4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 12 + lineCount: 1 + - id: "G4RS" + name: "Spec Example 2.17. Quoted Scalars" + localPath: yaml-test-suite/G4RS/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 177 + lineCount: 7 + - id: "G5U8" + name: "Plain dashes in flow sequence" + localPath: yaml-test-suite/G5U8/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 13 + lineCount: 2 + - id: "G7JE" + name: "Multiline implicit keys" + localPath: yaml-test-suite/G7JE/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 16 + lineCount: 3 + - id: "G992" + name: "Spec Example 8.9. Folded Scalar" + localPath: yaml-test-suite/G992/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 5 + - id: "G9HC" + name: "Invalid anchor in zero indented sequence" + localPath: yaml-test-suite/G9HC/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 25 + lineCount: 5 + - id: "GDY7" + name: "Comment that looks like a mapping key" + localPath: yaml-test-suite/GDY7/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 31 + lineCount: 2 + - id: "GH63" + name: "Mixed Block Mapping (explicit to implicit)" + localPath: yaml-test-suite/GH63/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 3 + - id: "GT5M" + name: "Node anchor in sequence" + localPath: yaml-test-suite/GT5M/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 22 + lineCount: 3 + - id: "H2RW" + name: "Blank lines" + localPath: yaml-test-suite/H2RW/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 52 + lineCount: 12 + - id: "H3Z8" + name: "Literal unicode" + localPath: yaml-test-suite/H3Z8/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 35 + lineCount: 2 + - id: "H7J7" + name: "Node anchor not indented" + localPath: yaml-test-suite/H7J7/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 21 + lineCount: 3 + - id: "H7TQ" + name: "Extra words on %YAML directive" + localPath: yaml-test-suite/H7TQ/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 18 + lineCount: 2 + - id: "HM87/00" + name: "Scalars in flow start with syntax char" + localPath: yaml-test-suite/HM87/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 5 + lineCount: 1 + - id: "HM87/01" + name: "Scalars in flow start with syntax char" + localPath: yaml-test-suite/HM87/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 5 + lineCount: 1 + - id: "HMK4" + name: "Spec Example 2.16. Indentation determines scope" + localPath: yaml-test-suite/HMK4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 138 + lineCount: 7 + - id: "HMQ5" + name: "Spec Example 6.23. Node Properties" + localPath: yaml-test-suite/HMQ5/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 43 + lineCount: 3 + - id: "HRE5" + name: "Double quoted scalar with escaped single quote" + localPath: yaml-test-suite/HRE5/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 31 + lineCount: 2 + - id: "HS5T" + name: "Spec Example 7.12. Plain Lines" + localPath: yaml-test-suite/HS5T/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 46 + lineCount: 4 + - id: "HU3P" + name: "Invalid Mapping in plain scalar" + localPath: yaml-test-suite/HU3P/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 29 + lineCount: 3 + - id: "HWV9" + name: "Document-end marker" + localPath: yaml-test-suite/HWV9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 4 + lineCount: 1 + - id: "J3BT" + name: "Spec Example 5.12. Tabs and Spaces" + localPath: yaml-test-suite/J3BT/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 96 + lineCount: 6 + - id: "J5UC" + name: "Multiple Pair Block Mapping" + localPath: yaml-test-suite/J5UC/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 30 + lineCount: 3 + - id: "J7PZ" + name: "Spec Example 2.26. Ordered Mappings" + localPath: yaml-test-suite/J7PZ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 318 + lineCount: 11 + - id: "J7VC" + name: "Empty Lines Between Mapping Elements" + localPath: yaml-test-suite/J7VC/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 18 + lineCount: 4 + - id: "J9HZ" + name: "Spec Example 2.9. Single Document with Two Comments" + localPath: yaml-test-suite/J9HZ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 115 + lineCount: 8 + - id: "JEF9/00" + name: "Trailing whitespace in streams" + localPath: yaml-test-suite/JEF9/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 7 + lineCount: 3 + - id: "JEF9/01" + name: "Trailing whitespace in streams" + localPath: yaml-test-suite/JEF9/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 9 + lineCount: 2 + - id: "JEF9/02" + name: "Trailing whitespace in streams" + localPath: yaml-test-suite/JEF9/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 8 + lineCount: 1 + - id: "JHB9" + name: "Spec Example 2.7. Two Documents in a Stream" + localPath: yaml-test-suite/JHB9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 130 + lineCount: 10 + - id: "JKF3" + name: "Multiline unidented double quoted block key" + localPath: yaml-test-suite/JKF3/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 17 + lineCount: 2 + - id: "JQ4R" + name: "Spec Example 8.14. Block Sequence" + localPath: yaml-test-suite/JQ4R/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 40 + lineCount: 3 + - id: "JR7V" + name: "Question marks in scalars" + localPath: yaml-test-suite/JR7V/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 128 + lineCount: 8 + - id: "JS2J" + name: "Spec Example 6.29. Node Anchors" + localPath: yaml-test-suite/JS2J/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 59 + lineCount: 2 + - id: "JTV5" + name: "Block Mapping with Multiline Scalars" + localPath: yaml-test-suite/JTV5/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 31 + lineCount: 6 + - id: "JY7Z" + name: "Trailing content that looks like a mapping" + localPath: yaml-test-suite/JY7Z/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 66 + lineCount: 3 + - id: "K3WX" + name: "Colon and adjacent value after comment on next line" + localPath: yaml-test-suite/K3WX/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 31 + lineCount: 3 + - id: "K4SU" + name: "Multiple Entry Block Sequence" + localPath: yaml-test-suite/K4SU/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 17 + lineCount: 3 + - id: "K527" + name: "Spec Example 6.6. Line Folding" + localPath: yaml-test-suite/K527/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 32 + lineCount: 7 + - id: "K54U" + name: "Tab after document header" + localPath: yaml-test-suite/K54U/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 11 + lineCount: 1 + - id: "K858" + name: "Spec Example 8.6. Empty Scalar Chomping" + localPath: yaml-test-suite/K858/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 30 + lineCount: 6 + - id: "KH5V/00" + name: "Inline tabs in double quoted" + localPath: yaml-test-suite/KH5V/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 1 + - id: "KH5V/01" + name: "Inline tabs in double quoted" + localPath: yaml-test-suite/KH5V/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 1 + - id: "KH5V/02" + name: "Inline tabs in double quoted" + localPath: yaml-test-suite/KH5V/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 1 + - id: "KK5P" + name: "Various combinations of explicit block mappings" + localPath: yaml-test-suite/KK5P/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 124 + lineCount: 16 + - id: "KMK3" + name: "Block Submapping" + localPath: yaml-test-suite/KMK3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 3 + - id: "KS4U" + name: "Invalid item after end of flow sequence" + localPath: yaml-test-suite/KS4U/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 35 + lineCount: 5 + - id: "KSS4" + name: "Scalars on --- line" + localPath: yaml-test-suite/KSS4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 34 + lineCount: 3 + - id: "L24T/00" + name: "Trailing line of spaces" + localPath: yaml-test-suite/L24T/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 3 + - id: "L24T/01" + name: "Trailing line of spaces" + localPath: yaml-test-suite/L24T/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 14 + lineCount: 2 + - id: "L383" + name: "Two scalar docs with trailing comments" + localPath: yaml-test-suite/L383/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 38 + lineCount: 2 + - id: "L94M" + name: "Tags in Explicit Mapping" + localPath: yaml-test-suite/L94M/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 35 + lineCount: 4 + - id: "L9U5" + name: "Spec Example 7.11. Plain Implicit Keys" + localPath: yaml-test-suite/L9U5/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 55 + lineCount: 3 + - id: "LE5A" + name: "Spec Example 7.24. Flow Nodes" + localPath: yaml-test-suite/LE5A/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 50 + lineCount: 5 + - id: "LHL4" + name: "Invalid tag" + localPath: yaml-test-suite/LHL4/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 25 + lineCount: 2 + - id: "LP6E" + name: "Whitespace After Scalars in Flow" + localPath: yaml-test-suite/LP6E/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 70 + lineCount: 6 + - id: "LQZ7" + name: "Spec Example 7.4. Double Quoted Implicit Keys" + localPath: yaml-test-suite/LQZ7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 59 + lineCount: 3 + - id: "LX3P" + name: "Implicit Flow Mapping Key on one line" + localPath: yaml-test-suite/LX3P/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 14 + lineCount: 1 + - id: "M29M" + name: "Literal Block Scalar" + localPath: yaml-test-suite/M29M/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 8 + - id: "M2N8/00" + name: "Question mark edge cases" + localPath: yaml-test-suite/M2N8/00/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 8 + lineCount: 1 + - id: "M2N8/01" + name: "Question mark edge cases" + localPath: yaml-test-suite/M2N8/01/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 8 + lineCount: 1 + - id: "M5C3" + name: "Spec Example 8.21. Block Scalar Nodes" + localPath: yaml-test-suite/M5C3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 48 + lineCount: 6 + - id: "M5DY" + name: "Spec Example 2.11. Mapping between Sequences" + localPath: yaml-test-suite/M5DY/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 142 + lineCount: 9 + - id: "M6YH" + name: "Block sequence indentation" + localPath: yaml-test-suite/M6YH/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 27 + lineCount: 6 + - id: "M7A3" + name: "Spec Example 9.3. Bare Documents" + localPath: yaml-test-suite/M7A3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 74 + lineCount: 7 + - id: "M7NX" + name: "Nested flow collections" + localPath: yaml-test-suite/M7NX/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 44 + lineCount: 8 + - id: "M9B4" + name: "Spec Example 8.7. Literal Scalar" + localPath: yaml-test-suite/M9B4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 20 + lineCount: 5 + - id: "MJS9" + name: "Spec Example 6.7. Block Folding" + localPath: yaml-test-suite/MJS9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 6 + - id: "MUS6/00" + name: "Directive variants" + localPath: yaml-test-suite/MUS6/00/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 18 + lineCount: 2 + - id: "MUS6/01" + name: "Directive variants" + localPath: yaml-test-suite/MUS6/01/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 28 + lineCount: 4 + - id: "MUS6/02" + name: "Directive variants" + localPath: yaml-test-suite/MUS6/02/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 2 + - id: "MUS6/03" + name: "Directive variants" + localPath: yaml-test-suite/MUS6/03/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 2 + - id: "MUS6/04" + name: "Directive variants" + localPath: yaml-test-suite/MUS6/04/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 25 + lineCount: 2 + - id: "MUS6/05" + name: "Directive variants" + localPath: yaml-test-suite/MUS6/05/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 13 + lineCount: 2 + - id: "MUS6/06" + name: "Directive variants" + localPath: yaml-test-suite/MUS6/06/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 2 + - id: "MXS3" + name: "Flow Mapping in Block Sequence" + localPath: yaml-test-suite/MXS3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 9 + lineCount: 1 + - id: "MYW6" + name: "Block Scalar Strip" + localPath: yaml-test-suite/MYW6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 15 + lineCount: 5 + - id: "MZX3" + name: "Non-Specific Tags on Scalars" + localPath: yaml-test-suite/MZX3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 70 + lineCount: 6 + - id: "N4JP" + name: "Bad indentation in mapping" + localPath: yaml-test-suite/N4JP/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 48 + lineCount: 3 + - id: "N782" + name: "Invalid document markers in flow style" + localPath: yaml-test-suite/N782/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 14 + lineCount: 4 + - id: "NAT4" + name: "Various empty or newline only quoted strings" + localPath: yaml-test-suite/NAT4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 86 + lineCount: 23 + - id: "NB6Z" + name: "Multiline plain value with tabs on empty lines" + localPath: yaml-test-suite/NB6Z/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 31 + lineCount: 5 + - id: "NHX8" + name: "Empty Lines at End of Document" + localPath: yaml-test-suite/NHX8/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 4 + lineCount: 3 + - id: "NJ66" + name: "Multiline plain flow mapping key" + localPath: yaml-test-suite/NJ66/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 53 + lineCount: 4 + - id: "NKF9" + name: "Empty keys in block and flow mapping" + localPath: yaml-test-suite/NKF9/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 120 + lineCount: 13 + - id: "NP9H" + name: "Spec Example 7.5. Double Quoted Line Breaks" + localPath: yaml-test-suite/NP9H/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 63 + lineCount: 5 + - id: "P2AD" + name: "Spec Example 8.1. Block Scalar Header" + localPath: yaml-test-suite/P2AD/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 143 + lineCount: 9 + - id: "P2EQ" + name: "Invalid sequene item on same line as previous item" + localPath: yaml-test-suite/P2EQ/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 24 + lineCount: 2 + - id: "P76L" + name: "Spec Example 6.19. Secondary Tag Handle" + localPath: yaml-test-suite/P76L/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 74 + lineCount: 3 + - id: "P94K" + name: "Spec Example 6.11. Multi-Line Comments" + localPath: yaml-test-suite/P94K/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 44 + lineCount: 5 + - id: "PBJ2" + name: "Spec Example 2.3. Mapping Scalars to Sequences" + localPath: yaml-test-suite/PBJ2/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 133 + lineCount: 8 + - id: "PRH3" + name: "Spec Example 7.9. Single Quoted Lines" + localPath: yaml-test-suite/PRH3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 50 + lineCount: 4 + - id: "PUW8" + name: "Document start on last line" + localPath: yaml-test-suite/PUW8/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 13 + lineCount: 3 + - id: "PW8X" + name: "Anchors on Empty Scalars" + localPath: yaml-test-suite/PW8X/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 65 + lineCount: 12 + - id: "Q4CL" + name: "Trailing content after quoted value" + localPath: yaml-test-suite/Q4CL/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 65 + lineCount: 3 + - id: "Q5MG" + name: "Tab at beginning of line followed by a flow mapping" + localPath: yaml-test-suite/Q5MG/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 4 + lineCount: 1 + - id: "Q88A" + name: "Spec Example 7.23. Flow Content" + localPath: yaml-test-suite/Q88A/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 38 + lineCount: 5 + - id: "Q8AD" + name: "Spec Example 7.5. Double Quoted Line Breaks [1.3]" + localPath: yaml-test-suite/Q8AD/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 66 + lineCount: 6 + - id: "Q9WF" + name: "Spec Example 6.12. Separation Spaces" + localPath: yaml-test-suite/Q9WF/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 97 + lineCount: 6 + - id: "QB6E" + name: "Wrong indented multiline quoted scalar" + localPath: yaml-test-suite/QB6E/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 20 + lineCount: 4 + - id: "QF4Y" + name: "Spec Example 7.19. Single Pair Flow Mappings" + localPath: yaml-test-suite/QF4Y/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 13 + lineCount: 3 + - id: "QLJ7" + name: "Tag shorthand used in documents but only defined in the first" + localPath: yaml-test-suite/QLJ7/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 93 + lineCount: 7 + - id: "QT73" + name: "Comment and document-end marker" + localPath: yaml-test-suite/QT73/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 14 + lineCount: 2 + - id: "R4YG" + name: "Spec Example 8.2. Block Indentation Indicator" + localPath: yaml-test-suite/R4YG/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 69 + lineCount: 11 + - id: "R52L" + name: "Nested flow mapping sequence and mappings" + localPath: yaml-test-suite/R52L/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 59 + lineCount: 2 + - id: "RHX7" + name: "YAML directive without document end marker" + localPath: yaml-test-suite/RHX7/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 29 + lineCount: 4 + - id: "RLU9" + name: "Sequence Indent" + localPath: yaml-test-suite/RLU9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 4 + - id: "RR7F" + name: "Mixed Block Mapping (implicit to explicit)" + localPath: yaml-test-suite/RR7F/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 3 + - id: "RTP8" + name: "Spec Example 9.2. Document Markers" + localPath: yaml-test-suite/RTP8/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 36 + lineCount: 4 + - id: "RXY3" + name: "Invalid document-end marker in single quoted string" + localPath: yaml-test-suite/RXY3/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 12 + lineCount: 4 + - id: "RZP5" + name: "Various Trailing Comments [1.3]" + localPath: yaml-test-suite/RZP5/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 157 + lineCount: 15 + - id: "RZT7" + name: "Spec Example 2.28. Log File" + localPath: yaml-test-suite/RZT7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 411 + lineCount: 26 + - id: "S3PD" + name: "Spec Example 8.18. Implicit Block Mapping Entries" + localPath: yaml-test-suite/S3PD/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 62 + lineCount: 4 + - id: "S4GJ" + name: "Invalid text after block scalar indicator" + localPath: yaml-test-suite/S4GJ/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 39 + lineCount: 3 + - id: "S4JQ" + name: "Spec Example 6.28. Non-Specific Tags" + localPath: yaml-test-suite/S4JQ/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 55 + lineCount: 4 + - id: "S4T7" + name: "Document with footer" + localPath: yaml-test-suite/S4T7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 13 + lineCount: 2 + - id: "S7BG" + name: "Colon followed by comma" + localPath: yaml-test-suite/S7BG/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 9 + lineCount: 2 + - id: "S98Z" + name: "Block scalar with more spaces than first content line" + localPath: yaml-test-suite/S98Z/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 42 + lineCount: 5 + - id: "S9E8" + name: "Spec Example 5.3. Block Structure Indicators" + localPath: yaml-test-suite/S9E8/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 62 + lineCount: 7 + - id: "SBG9" + name: "Flow Sequence in Flow Mapping" + localPath: yaml-test-suite/SBG9/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 23 + lineCount: 1 + - id: "SF5V" + name: "Duplicate YAML directive" + localPath: yaml-test-suite/SF5V/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 24 + lineCount: 3 + - id: "SKE5" + name: "Anchor before zero indented sequence" + localPath: yaml-test-suite/SKE5/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 5 + - id: "SM9W/00" + name: "Single character streams" + localPath: yaml-test-suite/SM9W/00/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 1 + lineCount: 0 + - id: "SM9W/01" + name: "Single character streams" + localPath: yaml-test-suite/SM9W/01/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 1 + lineCount: 0 + - id: "SR86" + name: "Anchor plus Alias" + localPath: yaml-test-suite/SR86/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 27 + lineCount: 2 + - id: "SSW6" + name: "Spec Example 7.7. Single Quoted Characters [1.3]" + localPath: yaml-test-suite/SSW6/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 2 + - id: "SU5Z" + name: "Comment without whitespace after doublequoted scalar" + localPath: yaml-test-suite/SU5Z/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 30 + lineCount: 1 + - id: "SU74" + name: "Anchor and alias as mapping key" + localPath: yaml-test-suite/SU74/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 39 + lineCount: 2 + - id: "SY6V" + name: "Anchor before sequence entry on same line" + localPath: yaml-test-suite/SY6V/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 25 + lineCount: 1 + - id: "SYW4" + name: "Spec Example 2.2. Mapping Scalars to Scalars" + localPath: yaml-test-suite/SYW4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 80 + lineCount: 3 + - id: "T26H" + name: "Spec Example 8.8. Literal Content [1.3]" + localPath: yaml-test-suite/T26H/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 47 + lineCount: 9 + - id: "T4YY" + name: "Spec Example 7.9. Single Quoted Lines [1.3]" + localPath: yaml-test-suite/T4YY/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 54 + lineCount: 5 + - id: "T5N4" + name: "Spec Example 8.7. Literal Scalar [1.3]" + localPath: yaml-test-suite/T5N4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 24 + lineCount: 5 + - id: "T833" + name: "Flow mapping missing a separating comma" + localPath: yaml-test-suite/T833/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 24 + lineCount: 4 + - id: "TD5N" + name: "Invalid scalar after sequence" + localPath: yaml-test-suite/TD5N/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 24 + lineCount: 3 + - id: "TE2A" + name: "Spec Example 8.16. Block Mappings" + localPath: yaml-test-suite/TE2A/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 27 + lineCount: 2 + - id: "TL85" + name: "Spec Example 6.8. Flow Folding" + localPath: yaml-test-suite/TL85/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 28 + lineCount: 7 + - id: "TS54" + name: "Folded Block Scalar" + localPath: yaml-test-suite/TS54/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 22 + lineCount: 8 + - id: "U3C3" + name: "Spec Example 6.16. “TAG” directive" + localPath: yaml-test-suite/U3C3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 51 + lineCount: 3 + - id: "U3XV" + name: "Node and Mapping Key Anchors" + localPath: yaml-test-suite/U3XV/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 190 + lineCount: 17 + - id: "U44R" + name: "Bad indentation in mapping (2)" + localPath: yaml-test-suite/U44R/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 50 + lineCount: 3 + - id: "U99R" + name: "Invalid comma in tag" + localPath: yaml-test-suite/U99R/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 13 + lineCount: 1 + - id: "U9NS" + name: "Spec Example 2.8. Play by Play Feed from a Game" + localPath: yaml-test-suite/U9NS/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 125 + lineCount: 10 + - id: "UDM2" + name: "Plain URL in flow mapping" + localPath: yaml-test-suite/UDM2/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 30 + lineCount: 1 + - id: "UDR7" + name: "Spec Example 5.4. Flow Collection Indicators" + localPath: yaml-test-suite/UDR7/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 59 + lineCount: 2 + - id: "UGM3" + name: "Spec Example 2.27. Invoice" + localPath: yaml-test-suite/UGM3/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 644 + lineCount: 29 + - id: "UKK6/00" + name: "Syntax character edge cases" + localPath: yaml-test-suite/UKK6/00/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 4 + lineCount: 1 + - id: "UKK6/01" + name: "Syntax character edge cases" + localPath: yaml-test-suite/UKK6/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 3 + lineCount: 1 + - id: "UKK6/02" + name: "Syntax character edge cases" + localPath: yaml-test-suite/UKK6/02/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 2 + lineCount: 1 + - id: "UT92" + name: "Spec Example 9.4. Explicit Documents" + localPath: yaml-test-suite/UT92/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 43 + lineCount: 7 + - id: "UV7Q" + name: "Legal tab after indentation" + localPath: yaml-test-suite/UV7Q/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 13 + lineCount: 3 + - id: "V55R" + name: "Aliases in Block Sequence" + localPath: yaml-test-suite/V55R/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 24 + lineCount: 4 + - id: "V9D5" + name: "Spec Example 8.19. Compact Block Mappings" + localPath: yaml-test-suite/V9D5/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 46 + lineCount: 3 + - id: "VJP3/00" + name: "Flow collections over many lines" + localPath: yaml-test-suite/VJP3/00/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 13 + lineCount: 5 + - id: "VJP3/01" + name: "Flow collections over many lines" + localPath: yaml-test-suite/VJP3/01/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 17 + lineCount: 5 + - id: "W42U" + name: "Spec Example 8.15. Block Sequence Entry Types" + localPath: yaml-test-suite/W42U/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 92 + lineCount: 6 + - id: "W4TN" + name: "Spec Example 9.5. Directives Documents" + localPath: yaml-test-suite/W4TN/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 61 + lineCount: 8 + - id: "W5VH" + name: "Allowed characters in alias" + localPath: yaml-test-suite/W5VH/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 43 + lineCount: 2 + - id: "W9L4" + name: "Literal block scalar with more spaces in first line" + localPath: yaml-test-suite/W9L4/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 71 + lineCount: 5 + - id: "WZ62" + name: "Spec Example 7.2. Empty Content" + localPath: yaml-test-suite/WZ62/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 34 + lineCount: 4 + - id: "X38W" + name: "Aliases in Flow Objects" + localPath: yaml-test-suite/X38W/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 37 + lineCount: 1 + - id: "X4QW" + name: "Comment without whitespace after block scalar indicator" + localPath: yaml-test-suite/X4QW/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 27 + lineCount: 2 + - id: "X8DW" + name: "Explicit key and value seperated by comment" + localPath: yaml-test-suite/X8DW/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 28 + lineCount: 4 + - id: "XLQ9" + name: "Multiline scalar that looks like a YAML directive" + localPath: yaml-test-suite/XLQ9/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 21 + lineCount: 3 + - id: "XV9V" + name: "Spec Example 6.5. Empty Lines [1.3]" + localPath: yaml-test-suite/XV9V/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 79 + lineCount: 8 + - id: "XW4D" + name: "Various Trailing Comments" + localPath: yaml-test-suite/XW4D/in.yaml + expected: parse-ok + oracle: none + status: passing + byteCount: 158 + lineCount: 16 + - id: "Y2GN" + name: "Anchor with colon in the middle" + localPath: yaml-test-suite/Y2GN/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 24 + lineCount: 2 + - id: "Y79Y/000" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/000/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 16 + lineCount: 3 + - id: "Y79Y/001" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/001/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 17 + lineCount: 3 + - id: "Y79Y/002" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/002/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 14 + lineCount: 4 + - id: "Y79Y/003" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/003/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 18 + lineCount: 4 + - id: "Y79Y/004" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/004/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 4 + lineCount: 1 + - id: "Y79Y/005" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/005/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 5 + lineCount: 1 + - id: "Y79Y/006" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/006/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 4 + lineCount: 1 + - id: "Y79Y/007" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/007/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 8 + lineCount: 2 + - id: "Y79Y/008" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/008/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 7 + lineCount: 1 + - id: "Y79Y/009" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/009/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 14 + lineCount: 2 + - id: "Y79Y/010" + name: "Tabs in various contexts" + localPath: yaml-test-suite/Y79Y/010/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 5 + lineCount: 1 + - id: "YD5X" + name: "Spec Example 2.5. Sequence of Sequences" + localPath: yaml-test-suite/YD5X/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 84 + lineCount: 3 + - id: "YJV2" + name: "Dash in flow sequence" + localPath: yaml-test-suite/YJV2/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 4 + lineCount: 1 + - id: "Z67P" + name: "Spec Example 8.21. Block Scalar Nodes [1.3]" + localPath: yaml-test-suite/Z67P/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 43 + lineCount: 4 + - id: "Z9M4" + name: "Spec Example 6.22. Global Tag Prefix" + localPath: yaml-test-suite/Z9M4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 54 + lineCount: 3 + - id: "ZCZ6" + name: "Invalid mapping in plain single line value" + localPath: yaml-test-suite/ZCZ6/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 11 + lineCount: 1 + - id: "ZF4X" + name: "Spec Example 2.6. Mapping of Mappings" + localPath: yaml-test-suite/ZF4X/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 80 + lineCount: 5 + - id: "ZH7C" + name: "Anchors in Mapping" + localPath: yaml-test-suite/ZH7C/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 16 + lineCount: 2 + - id: "ZK9H" + name: "Nested top level flow mapping" + localPath: yaml-test-suite/ZK9H/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 4 + - id: "ZL4Z" + name: "Invalid nested mapping" + localPath: yaml-test-suite/ZL4Z/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 14 + lineCount: 2 + - id: "ZVH3" + name: "Wrong indented sequence item" + localPath: yaml-test-suite/ZVH3/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 22 + lineCount: 2 + - id: "ZWK4" + name: "Key with anchor after missing explicit mapping value" + localPath: yaml-test-suite/ZWK4/in.yaml + expected: parse-ok + oracle: json + status: passing + byteCount: 26 + lineCount: 4 + - id: "ZXT5" + name: "Implicit key followed by newline and adjacent value" + localPath: yaml-test-suite/ZXT5/in.yaml + expected: reject + oracle: none + status: passing + byteCount: 19 + lineCount: 2 diff --git a/Tests/Fixtures/yaml-test-suite/229Q/in.json b/Tests/Fixtures/yaml-test-suite/229Q/in.json new file mode 100644 index 0000000..3d3b2d9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/229Q/in.json @@ -0,0 +1,12 @@ +[ + { + "name": "Mark McGwire", + "hr": 65, + "avg": 0.278 + }, + { + "name": "Sammy Sosa", + "hr": 63, + "avg": 0.288 + } +] diff --git a/Tests/Fixtures/yaml-test-suite/229Q/in.yaml b/Tests/Fixtures/yaml-test-suite/229Q/in.yaml new file mode 100644 index 0000000..430f6b3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/229Q/in.yaml @@ -0,0 +1,8 @@ +- + name: Mark McGwire + hr: 65 + avg: 0.278 +- + name: Sammy Sosa + hr: 63 + avg: 0.288 diff --git a/Tests/Fixtures/yaml-test-suite/229Q/test.event b/Tests/Fixtures/yaml-test-suite/229Q/test.event new file mode 100644 index 0000000..fc75880 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/229Q/test.event @@ -0,0 +1,22 @@ ++STR ++DOC ++SEQ ++MAP +=VAL :name +=VAL :Mark McGwire +=VAL :hr +=VAL :65 +=VAL :avg +=VAL :0.278 +-MAP ++MAP +=VAL :name +=VAL :Sammy Sosa +=VAL :hr +=VAL :63 +=VAL :avg +=VAL :0.288 +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/236B/error b/Tests/Fixtures/yaml-test-suite/236B/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/236B/in.yaml b/Tests/Fixtures/yaml-test-suite/236B/in.yaml new file mode 100644 index 0000000..254e6fc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/236B/in.yaml @@ -0,0 +1,3 @@ +foo: + bar +invalid diff --git a/Tests/Fixtures/yaml-test-suite/236B/test.event b/Tests/Fixtures/yaml-test-suite/236B/test.event new file mode 100644 index 0000000..83d95a7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/236B/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :bar diff --git a/Tests/Fixtures/yaml-test-suite/26DV/in.json b/Tests/Fixtures/yaml-test-suite/26DV/in.json new file mode 100644 index 0000000..508c2c1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/26DV/in.json @@ -0,0 +1,18 @@ +{ + "top1": { + "key1": "scalar1" + }, + "top2": { + "key2": "scalar2" + }, + "top3": { + "scalar1": "scalar3" + }, + "top4": { + "scalar2": "scalar4" + }, + "top5": "scalar5", + "top6": { + "key6": "scalar6" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/26DV/in.yaml b/Tests/Fixtures/yaml-test-suite/26DV/in.yaml new file mode 100644 index 0000000..5df48e7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/26DV/in.yaml @@ -0,0 +1,12 @@ +"top1" : + "key1" : &alias1 scalar1 +'top2' : + 'key2' : &alias2 scalar2 +top3: &node3 + *alias1 : scalar3 +top4: + *alias2 : scalar4 +top5 : + scalar5 +top6: + &anchor6 'key6' : scalar6 diff --git a/Tests/Fixtures/yaml-test-suite/26DV/test.event b/Tests/Fixtures/yaml-test-suite/26DV/test.event new file mode 100644 index 0000000..e683fa7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/26DV/test.event @@ -0,0 +1,33 @@ ++STR ++DOC ++MAP +=VAL "top1 ++MAP +=VAL "key1 +=VAL &alias1 :scalar1 +-MAP +=VAL 'top2 ++MAP +=VAL 'key2 +=VAL &alias2 :scalar2 +-MAP +=VAL :top3 ++MAP &node3 +=ALI *alias1 +=VAL :scalar3 +-MAP +=VAL :top4 ++MAP +=ALI *alias2 +=VAL :scalar4 +-MAP +=VAL :top5 +=VAL :scalar5 +=VAL :top6 ++MAP +=VAL &anchor6 'key6 +=VAL :scalar6 +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/27NA/in.json b/Tests/Fixtures/yaml-test-suite/27NA/in.json new file mode 100644 index 0000000..8ee55ad --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/27NA/in.json @@ -0,0 +1 @@ +"text" diff --git a/Tests/Fixtures/yaml-test-suite/27NA/in.yaml b/Tests/Fixtures/yaml-test-suite/27NA/in.yaml new file mode 100644 index 0000000..62204de --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/27NA/in.yaml @@ -0,0 +1,2 @@ +%YAML 1.2 +--- text diff --git a/Tests/Fixtures/yaml-test-suite/27NA/test.event b/Tests/Fixtures/yaml-test-suite/27NA/test.event new file mode 100644 index 0000000..4caf24e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/27NA/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :text +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2AUY/in.json b/Tests/Fixtures/yaml-test-suite/2AUY/in.json new file mode 100644 index 0000000..87bffdd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2AUY/in.json @@ -0,0 +1,6 @@ +[ + "a", + "b", + 42, + "d" +] diff --git a/Tests/Fixtures/yaml-test-suite/2AUY/in.yaml b/Tests/Fixtures/yaml-test-suite/2AUY/in.yaml new file mode 100644 index 0000000..5152961 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2AUY/in.yaml @@ -0,0 +1,4 @@ + - !!str a + - b + - !!int 42 + - d diff --git a/Tests/Fixtures/yaml-test-suite/2AUY/test.event b/Tests/Fixtures/yaml-test-suite/2AUY/test.event new file mode 100644 index 0000000..9dfb913 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2AUY/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ +=VAL :a +=VAL :b +=VAL :42 +=VAL :d +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2CMS/error b/Tests/Fixtures/yaml-test-suite/2CMS/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/2CMS/in.yaml b/Tests/Fixtures/yaml-test-suite/2CMS/in.yaml new file mode 100644 index 0000000..72d31b1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2CMS/in.yaml @@ -0,0 +1,3 @@ +this + is + invalid: x diff --git a/Tests/Fixtures/yaml-test-suite/2CMS/test.event b/Tests/Fixtures/yaml-test-suite/2CMS/test.event new file mode 100644 index 0000000..b8e31a8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2CMS/test.event @@ -0,0 +1,2 @@ ++STR ++DOC diff --git a/Tests/Fixtures/yaml-test-suite/2EBW/in.json b/Tests/Fixtures/yaml-test-suite/2EBW/in.json new file mode 100644 index 0000000..91f8dbf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2EBW/in.json @@ -0,0 +1,7 @@ +{ + "a!\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~": "safe", + "?foo": "safe question mark", + ":foo": "safe colon", + "-foo": "safe dash", + "this is#not": "a comment" +} diff --git a/Tests/Fixtures/yaml-test-suite/2EBW/in.yaml b/Tests/Fixtures/yaml-test-suite/2EBW/in.yaml new file mode 100644 index 0000000..3a5b0a3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2EBW/in.yaml @@ -0,0 +1,5 @@ +a!"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~: safe +?foo: safe question mark +:foo: safe colon +-foo: safe dash +this is#not: a comment diff --git a/Tests/Fixtures/yaml-test-suite/2EBW/test.event b/Tests/Fixtures/yaml-test-suite/2EBW/test.event new file mode 100644 index 0000000..b211714 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2EBW/test.event @@ -0,0 +1,16 @@ ++STR ++DOC ++MAP +=VAL :a!"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~ +=VAL :safe +=VAL :?foo +=VAL :safe question mark +=VAL ::foo +=VAL :safe colon +=VAL :-foo +=VAL :safe dash +=VAL :this is#not +=VAL :a comment +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2G84/00/error b/Tests/Fixtures/yaml-test-suite/2G84/00/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/2G84/00/in.yaml b/Tests/Fixtures/yaml-test-suite/2G84/00/in.yaml new file mode 100644 index 0000000..56974da --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/00/in.yaml @@ -0,0 +1 @@ +--- |0 diff --git a/Tests/Fixtures/yaml-test-suite/2G84/00/test.event b/Tests/Fixtures/yaml-test-suite/2G84/00/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/00/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/2G84/01/error b/Tests/Fixtures/yaml-test-suite/2G84/01/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/2G84/01/in.yaml b/Tests/Fixtures/yaml-test-suite/2G84/01/in.yaml new file mode 100644 index 0000000..52ef846 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/01/in.yaml @@ -0,0 +1 @@ +--- |10 diff --git a/Tests/Fixtures/yaml-test-suite/2G84/01/test.event b/Tests/Fixtures/yaml-test-suite/2G84/01/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/01/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/2G84/02/in.json b/Tests/Fixtures/yaml-test-suite/2G84/02/in.json new file mode 100644 index 0000000..e16c76d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/02/in.json @@ -0,0 +1 @@ +"" diff --git a/Tests/Fixtures/yaml-test-suite/2G84/02/in.yaml b/Tests/Fixtures/yaml-test-suite/2G84/02/in.yaml new file mode 100644 index 0000000..9d09488 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/02/in.yaml @@ -0,0 +1 @@ +--- |1- \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/2G84/02/test.event b/Tests/Fixtures/yaml-test-suite/2G84/02/test.event new file mode 100644 index 0000000..f8b7b25 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/02/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL | +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2G84/03/in.json b/Tests/Fixtures/yaml-test-suite/2G84/03/in.json new file mode 100644 index 0000000..e16c76d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/03/in.json @@ -0,0 +1 @@ +"" diff --git a/Tests/Fixtures/yaml-test-suite/2G84/03/in.yaml b/Tests/Fixtures/yaml-test-suite/2G84/03/in.yaml new file mode 100644 index 0000000..3220349 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/03/in.yaml @@ -0,0 +1 @@ +--- |1+ \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/2G84/03/test.event b/Tests/Fixtures/yaml-test-suite/2G84/03/test.event new file mode 100644 index 0000000..f8b7b25 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2G84/03/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL | +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2JQS/in.yaml b/Tests/Fixtures/yaml-test-suite/2JQS/in.yaml new file mode 100644 index 0000000..d0a086d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2JQS/in.yaml @@ -0,0 +1,2 @@ +: a +: b diff --git a/Tests/Fixtures/yaml-test-suite/2JQS/test.event b/Tests/Fixtures/yaml-test-suite/2JQS/test.event new file mode 100644 index 0000000..0268179 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2JQS/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL : +=VAL :a +=VAL : +=VAL :b +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2LFX/in.json b/Tests/Fixtures/yaml-test-suite/2LFX/in.json new file mode 100644 index 0000000..810c96e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2LFX/in.json @@ -0,0 +1 @@ +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/2LFX/in.yaml b/Tests/Fixtures/yaml-test-suite/2LFX/in.yaml new file mode 100644 index 0000000..5068618 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2LFX/in.yaml @@ -0,0 +1,4 @@ +%FOO bar baz # Should be ignored + # with a warning. +--- +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/2LFX/test.event b/Tests/Fixtures/yaml-test-suite/2LFX/test.event new file mode 100644 index 0000000..324d096 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2LFX/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL "foo +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2SXE/in.json b/Tests/Fixtures/yaml-test-suite/2SXE/in.json new file mode 100644 index 0000000..d4470a6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2SXE/in.json @@ -0,0 +1,4 @@ +{ + "key": "value", + "foo": "key" +} diff --git a/Tests/Fixtures/yaml-test-suite/2SXE/in.yaml b/Tests/Fixtures/yaml-test-suite/2SXE/in.yaml new file mode 100644 index 0000000..243c466 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2SXE/in.yaml @@ -0,0 +1,3 @@ +&a: key: &a value +foo: + *a: diff --git a/Tests/Fixtures/yaml-test-suite/2SXE/test.event b/Tests/Fixtures/yaml-test-suite/2SXE/test.event new file mode 100644 index 0000000..712bf45 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2SXE/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL &a: :key +=VAL &a :value +=VAL :foo +=ALI *a: +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/2XXW/in.json b/Tests/Fixtures/yaml-test-suite/2XXW/in.json new file mode 100644 index 0000000..88daa64 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2XXW/in.json @@ -0,0 +1,5 @@ +{ + "Mark McGwire": null, + "Sammy Sosa": null, + "Ken Griff": null +} diff --git a/Tests/Fixtures/yaml-test-suite/2XXW/in.yaml b/Tests/Fixtures/yaml-test-suite/2XXW/in.yaml new file mode 100644 index 0000000..cf4943a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2XXW/in.yaml @@ -0,0 +1,7 @@ +# Sets are represented as a +# Mapping where each key is +# associated with a null value +--- !!set +? Mark McGwire +? Sammy Sosa +? Ken Griff diff --git a/Tests/Fixtures/yaml-test-suite/2XXW/test.event b/Tests/Fixtures/yaml-test-suite/2XXW/test.event new file mode 100644 index 0000000..3e2a946 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/2XXW/test.event @@ -0,0 +1,12 @@ ++STR ++DOC --- ++MAP +=VAL :Mark McGwire +=VAL : +=VAL :Sammy Sosa +=VAL : +=VAL :Ken Griff +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/33X3/in.json b/Tests/Fixtures/yaml-test-suite/33X3/in.json new file mode 100644 index 0000000..bc33116 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/33X3/in.json @@ -0,0 +1,5 @@ +[ + 1, + -2, + 33 +] diff --git a/Tests/Fixtures/yaml-test-suite/33X3/in.yaml b/Tests/Fixtures/yaml-test-suite/33X3/in.yaml new file mode 100644 index 0000000..c30779e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/33X3/in.yaml @@ -0,0 +1,4 @@ +--- +- !!int 1 +- !!int -2 +- !!int 33 diff --git a/Tests/Fixtures/yaml-test-suite/33X3/test.event b/Tests/Fixtures/yaml-test-suite/33X3/test.event new file mode 100644 index 0000000..54e9da1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/33X3/test.event @@ -0,0 +1,9 @@ ++STR ++DOC --- ++SEQ +=VAL :1 +=VAL :-2 +=VAL :33 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/35KP/in.json b/Tests/Fixtures/yaml-test-suite/35KP/in.json new file mode 100644 index 0000000..f8e731c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/35KP/in.json @@ -0,0 +1,7 @@ +{ + "a": "b" +} +[ + "c" +] +"d e" diff --git a/Tests/Fixtures/yaml-test-suite/35KP/in.yaml b/Tests/Fixtures/yaml-test-suite/35KP/in.yaml new file mode 100644 index 0000000..f0d91aa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/35KP/in.yaml @@ -0,0 +1,8 @@ +--- !!map +? a +: b +--- !!seq +- !!str c +--- !!str +d +e diff --git a/Tests/Fixtures/yaml-test-suite/35KP/test.event b/Tests/Fixtures/yaml-test-suite/35KP/test.event new file mode 100644 index 0000000..ab590fd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/35KP/test.event @@ -0,0 +1,16 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL :b +-MAP +-DOC ++DOC --- ++SEQ +=VAL :c +-SEQ +-DOC ++DOC --- +=VAL :d e +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/36F6/in.json b/Tests/Fixtures/yaml-test-suite/36F6/in.json new file mode 100644 index 0000000..026d7b4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/36F6/in.json @@ -0,0 +1,3 @@ +{ + "plain": "a b\nc" +} diff --git a/Tests/Fixtures/yaml-test-suite/36F6/in.yaml b/Tests/Fixtures/yaml-test-suite/36F6/in.yaml new file mode 100644 index 0000000..71600b8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/36F6/in.yaml @@ -0,0 +1,5 @@ +--- +plain: a + b + + c diff --git a/Tests/Fixtures/yaml-test-suite/36F6/test.event b/Tests/Fixtures/yaml-test-suite/36F6/test.event new file mode 100644 index 0000000..1221e48 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/36F6/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :plain +=VAL :a b\nc +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3ALJ/in.json b/Tests/Fixtures/yaml-test-suite/3ALJ/in.json new file mode 100644 index 0000000..71ea9d4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3ALJ/in.json @@ -0,0 +1,7 @@ +[ + [ + "s1_i1", + "s1_i2" + ], + "s2" +] diff --git a/Tests/Fixtures/yaml-test-suite/3ALJ/in.yaml b/Tests/Fixtures/yaml-test-suite/3ALJ/in.yaml new file mode 100644 index 0000000..4738eb1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3ALJ/in.yaml @@ -0,0 +1,3 @@ +- - s1_i1 + - s1_i2 +- s2 diff --git a/Tests/Fixtures/yaml-test-suite/3ALJ/test.event b/Tests/Fixtures/yaml-test-suite/3ALJ/test.event new file mode 100644 index 0000000..4f1622b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3ALJ/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++SEQ ++SEQ +=VAL :s1_i1 +=VAL :s1_i2 +-SEQ +=VAL :s2 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3GZX/in.json b/Tests/Fixtures/yaml-test-suite/3GZX/in.json new file mode 100644 index 0000000..4e09f3a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3GZX/in.json @@ -0,0 +1,6 @@ +{ + "First occurrence": "Foo", + "Second occurrence": "Foo", + "Override anchor": "Bar", + "Reuse anchor": "Bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/3GZX/in.yaml b/Tests/Fixtures/yaml-test-suite/3GZX/in.yaml new file mode 100644 index 0000000..3887676 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3GZX/in.yaml @@ -0,0 +1,4 @@ +First occurrence: &anchor Foo +Second occurrence: *anchor +Override anchor: &anchor Bar +Reuse anchor: *anchor diff --git a/Tests/Fixtures/yaml-test-suite/3GZX/test.event b/Tests/Fixtures/yaml-test-suite/3GZX/test.event new file mode 100644 index 0000000..d1aa38c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3GZX/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :First occurrence +=VAL &anchor :Foo +=VAL :Second occurrence +=ALI *anchor +=VAL :Override anchor +=VAL &anchor :Bar +=VAL :Reuse anchor +=ALI *anchor +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3HFZ/error b/Tests/Fixtures/yaml-test-suite/3HFZ/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/3HFZ/in.yaml b/Tests/Fixtures/yaml-test-suite/3HFZ/in.yaml new file mode 100644 index 0000000..7d30422 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3HFZ/in.yaml @@ -0,0 +1,3 @@ +--- +key: value +... invalid diff --git a/Tests/Fixtures/yaml-test-suite/3HFZ/test.event b/Tests/Fixtures/yaml-test-suite/3HFZ/test.event new file mode 100644 index 0000000..c3f805c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3HFZ/test.event @@ -0,0 +1,7 @@ ++STR ++DOC --- ++MAP +=VAL :key +=VAL :value +-MAP +-DOC ... diff --git a/Tests/Fixtures/yaml-test-suite/3MYT/in.json b/Tests/Fixtures/yaml-test-suite/3MYT/in.json new file mode 100644 index 0000000..1c50067 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3MYT/in.json @@ -0,0 +1 @@ +"k:#foo &a !t s" diff --git a/Tests/Fixtures/yaml-test-suite/3MYT/in.yaml b/Tests/Fixtures/yaml-test-suite/3MYT/in.yaml new file mode 100644 index 0000000..04a1240 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3MYT/in.yaml @@ -0,0 +1,3 @@ +--- +k:#foo + &a !t s diff --git a/Tests/Fixtures/yaml-test-suite/3MYT/test.event b/Tests/Fixtures/yaml-test-suite/3MYT/test.event new file mode 100644 index 0000000..e1f5738 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3MYT/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :k:#foo &a !t s +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3R3P/in.json b/Tests/Fixtures/yaml-test-suite/3R3P/in.json new file mode 100644 index 0000000..0ede90f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3R3P/in.json @@ -0,0 +1,3 @@ +[ + "a" +] diff --git a/Tests/Fixtures/yaml-test-suite/3R3P/in.yaml b/Tests/Fixtures/yaml-test-suite/3R3P/in.yaml new file mode 100644 index 0000000..bc2204c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3R3P/in.yaml @@ -0,0 +1,2 @@ +&sequence +- a diff --git a/Tests/Fixtures/yaml-test-suite/3R3P/test.event b/Tests/Fixtures/yaml-test-suite/3R3P/test.event new file mode 100644 index 0000000..6e03840 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3R3P/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ &sequence +=VAL :a +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/00/in.json b/Tests/Fixtures/yaml-test-suite/3RLN/00/in.json new file mode 100644 index 0000000..821166a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/00/in.json @@ -0,0 +1 @@ +"1 leading \ttab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/00/in.yaml b/Tests/Fixtures/yaml-test-suite/3RLN/00/in.yaml new file mode 100644 index 0000000..a6a23a8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/00/in.yaml @@ -0,0 +1,2 @@ +"1 leading + \ttab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/00/test.event b/Tests/Fixtures/yaml-test-suite/3RLN/00/test.event new file mode 100644 index 0000000..9472a18 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/00/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "1 leading \ttab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/01/in.json b/Tests/Fixtures/yaml-test-suite/3RLN/01/in.json new file mode 100644 index 0000000..29133b1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/01/in.json @@ -0,0 +1 @@ +"2 leading \ttab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/01/in.yaml b/Tests/Fixtures/yaml-test-suite/3RLN/01/in.yaml new file mode 100644 index 0000000..64057a8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/01/in.yaml @@ -0,0 +1,2 @@ +"2 leading + \ tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/01/test.event b/Tests/Fixtures/yaml-test-suite/3RLN/01/test.event new file mode 100644 index 0000000..b864b91 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/01/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "2 leading \ttab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/02/in.json b/Tests/Fixtures/yaml-test-suite/3RLN/02/in.json new file mode 100644 index 0000000..9f23c05 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/02/in.json @@ -0,0 +1 @@ +"3 leading tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/02/in.yaml b/Tests/Fixtures/yaml-test-suite/3RLN/02/in.yaml new file mode 100644 index 0000000..3b18adc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/02/in.yaml @@ -0,0 +1,2 @@ +"3 leading + tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/02/test.event b/Tests/Fixtures/yaml-test-suite/3RLN/02/test.event new file mode 100644 index 0000000..25ffca0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/02/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "3 leading tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/03/in.json b/Tests/Fixtures/yaml-test-suite/3RLN/03/in.json new file mode 100644 index 0000000..75b57d9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/03/in.json @@ -0,0 +1 @@ +"4 leading \t tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/03/in.yaml b/Tests/Fixtures/yaml-test-suite/3RLN/03/in.yaml new file mode 100644 index 0000000..815c713 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/03/in.yaml @@ -0,0 +1,2 @@ +"4 leading + \t tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/03/test.event b/Tests/Fixtures/yaml-test-suite/3RLN/03/test.event new file mode 100644 index 0000000..e3c2f45 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/03/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "4 leading \t tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/04/in.json b/Tests/Fixtures/yaml-test-suite/3RLN/04/in.json new file mode 100644 index 0000000..f73076a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/04/in.json @@ -0,0 +1 @@ +"5 leading \t tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/04/in.yaml b/Tests/Fixtures/yaml-test-suite/3RLN/04/in.yaml new file mode 100644 index 0000000..07e14f5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/04/in.yaml @@ -0,0 +1,2 @@ +"5 leading + \ tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/04/test.event b/Tests/Fixtures/yaml-test-suite/3RLN/04/test.event new file mode 100644 index 0000000..d240316 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/04/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "5 leading \t tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/05/in.json b/Tests/Fixtures/yaml-test-suite/3RLN/05/in.json new file mode 100644 index 0000000..46d1f8c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/05/in.json @@ -0,0 +1 @@ +"6 leading tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/05/in.yaml b/Tests/Fixtures/yaml-test-suite/3RLN/05/in.yaml new file mode 100644 index 0000000..75222d3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/05/in.yaml @@ -0,0 +1,2 @@ +"6 leading + tab" diff --git a/Tests/Fixtures/yaml-test-suite/3RLN/05/test.event b/Tests/Fixtures/yaml-test-suite/3RLN/05/test.event new file mode 100644 index 0000000..7e19da4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3RLN/05/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "6 leading tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/3UYS/in.json b/Tests/Fixtures/yaml-test-suite/3UYS/in.json new file mode 100644 index 0000000..6119ed9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3UYS/in.json @@ -0,0 +1,3 @@ +{ + "escaped slash": "a/b" +} diff --git a/Tests/Fixtures/yaml-test-suite/3UYS/in.yaml b/Tests/Fixtures/yaml-test-suite/3UYS/in.yaml new file mode 100644 index 0000000..e47bf72 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3UYS/in.yaml @@ -0,0 +1 @@ +escaped slash: "a\/b" diff --git a/Tests/Fixtures/yaml-test-suite/3UYS/test.event b/Tests/Fixtures/yaml-test-suite/3UYS/test.event new file mode 100644 index 0000000..6ef81d6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/3UYS/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :escaped slash +=VAL "a/b +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4ABK/in.yaml b/Tests/Fixtures/yaml-test-suite/4ABK/in.yaml new file mode 100644 index 0000000..c80379b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4ABK/in.yaml @@ -0,0 +1,5 @@ +{ +unquoted : "separate", +http://foo.com, +omitted value:, +} diff --git a/Tests/Fixtures/yaml-test-suite/4ABK/test.event b/Tests/Fixtures/yaml-test-suite/4ABK/test.event new file mode 100644 index 0000000..a1edb4d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4ABK/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP {} +=VAL :unquoted +=VAL "separate +=VAL :http://foo.com +=VAL : +=VAL :omitted value +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4CQQ/in.json b/Tests/Fixtures/yaml-test-suite/4CQQ/in.json new file mode 100644 index 0000000..018e242 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4CQQ/in.json @@ -0,0 +1,4 @@ +{ + "plain": "This unquoted scalar spans many lines.", + "quoted": "So does this quoted scalar.\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/4CQQ/in.yaml b/Tests/Fixtures/yaml-test-suite/4CQQ/in.yaml new file mode 100644 index 0000000..e0a8bfa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4CQQ/in.yaml @@ -0,0 +1,6 @@ +plain: + This unquoted scalar + spans many lines. + +quoted: "So does this + quoted scalar.\n" diff --git a/Tests/Fixtures/yaml-test-suite/4CQQ/test.event b/Tests/Fixtures/yaml-test-suite/4CQQ/test.event new file mode 100644 index 0000000..ea9d1bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4CQQ/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :plain +=VAL :This unquoted scalar spans many lines. +=VAL :quoted +=VAL "So does this quoted scalar.\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4EJS/error b/Tests/Fixtures/yaml-test-suite/4EJS/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/4EJS/in.yaml b/Tests/Fixtures/yaml-test-suite/4EJS/in.yaml new file mode 100644 index 0000000..b507e20 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4EJS/in.yaml @@ -0,0 +1,4 @@ +--- +a: + b: + c: value diff --git a/Tests/Fixtures/yaml-test-suite/4EJS/test.event b/Tests/Fixtures/yaml-test-suite/4EJS/test.event new file mode 100644 index 0000000..886e653 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4EJS/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :a diff --git a/Tests/Fixtures/yaml-test-suite/4FJ6/in.yaml b/Tests/Fixtures/yaml-test-suite/4FJ6/in.yaml new file mode 100644 index 0000000..3f4aabe --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4FJ6/in.yaml @@ -0,0 +1,4 @@ +--- +[ + [ a, [ [[b,c]]: d, e]]: 23 +] diff --git a/Tests/Fixtures/yaml-test-suite/4FJ6/test.event b/Tests/Fixtures/yaml-test-suite/4FJ6/test.event new file mode 100644 index 0000000..da361fd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4FJ6/test.event @@ -0,0 +1,24 @@ ++STR ++DOC --- ++SEQ [] ++MAP {} ++SEQ [] +=VAL :a ++SEQ [] ++MAP {} ++SEQ [] ++SEQ [] +=VAL :b +=VAL :c +-SEQ +-SEQ +=VAL :d +-MAP +=VAL :e +-SEQ +-SEQ +=VAL :23 +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4GC6/in.json b/Tests/Fixtures/yaml-test-suite/4GC6/in.json new file mode 100644 index 0000000..fdc456c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4GC6/in.json @@ -0,0 +1 @@ +"here's to \"quotes\"" diff --git a/Tests/Fixtures/yaml-test-suite/4GC6/in.yaml b/Tests/Fixtures/yaml-test-suite/4GC6/in.yaml new file mode 100644 index 0000000..3efcb91 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4GC6/in.yaml @@ -0,0 +1 @@ +'here''s to "quotes"' diff --git a/Tests/Fixtures/yaml-test-suite/4GC6/test.event b/Tests/Fixtures/yaml-test-suite/4GC6/test.event new file mode 100644 index 0000000..d1efb0e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4GC6/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL 'here's to "quotes" +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4H7K/error b/Tests/Fixtures/yaml-test-suite/4H7K/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/4H7K/in.yaml b/Tests/Fixtures/yaml-test-suite/4H7K/in.yaml new file mode 100644 index 0000000..686440d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4H7K/in.yaml @@ -0,0 +1,2 @@ +--- +[ a, b, c ] ] diff --git a/Tests/Fixtures/yaml-test-suite/4H7K/test.event b/Tests/Fixtures/yaml-test-suite/4H7K/test.event new file mode 100644 index 0000000..007493c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4H7K/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++SEQ +=VAL :a +=VAL :b +=VAL :c +-SEQ +-DOC diff --git a/Tests/Fixtures/yaml-test-suite/4HVU/error b/Tests/Fixtures/yaml-test-suite/4HVU/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/4HVU/in.yaml b/Tests/Fixtures/yaml-test-suite/4HVU/in.yaml new file mode 100644 index 0000000..d4118cb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4HVU/in.yaml @@ -0,0 +1,4 @@ +key: + - ok + - also ok + - wrong diff --git a/Tests/Fixtures/yaml-test-suite/4HVU/test.event b/Tests/Fixtures/yaml-test-suite/4HVU/test.event new file mode 100644 index 0000000..9e4de12 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4HVU/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :key ++SEQ +=VAL :ok +=VAL :also ok +-SEQ diff --git a/Tests/Fixtures/yaml-test-suite/4JVG/error b/Tests/Fixtures/yaml-test-suite/4JVG/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/4JVG/in.yaml b/Tests/Fixtures/yaml-test-suite/4JVG/in.yaml new file mode 100644 index 0000000..9afb769 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4JVG/in.yaml @@ -0,0 +1,4 @@ +top1: &node1 + &k1 key1: val1 +top2: &node2 + &v2 val2 diff --git a/Tests/Fixtures/yaml-test-suite/4JVG/test.event b/Tests/Fixtures/yaml-test-suite/4JVG/test.event new file mode 100644 index 0000000..5541cfd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4JVG/test.event @@ -0,0 +1,9 @@ ++STR ++DOC ++MAP +=VAL :top1 ++MAP &node1 +=VAL &k1 :key1 +=VAL :val1 +-MAP +=VAL :top2 diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/00/in.json b/Tests/Fixtures/yaml-test-suite/4MUZ/00/in.json new file mode 100644 index 0000000..c8c4105 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/00/in.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/00/in.yaml b/Tests/Fixtures/yaml-test-suite/4MUZ/00/in.yaml new file mode 100644 index 0000000..d80f798 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/00/in.yaml @@ -0,0 +1,2 @@ +{"foo" +: "bar"} diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/00/test.event b/Tests/Fixtures/yaml-test-suite/4MUZ/00/test.event new file mode 100644 index 0000000..c8fe433 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/00/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP {} +=VAL "foo +=VAL "bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/01/in.json b/Tests/Fixtures/yaml-test-suite/4MUZ/01/in.json new file mode 100644 index 0000000..c8c4105 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/01/in.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/01/in.yaml b/Tests/Fixtures/yaml-test-suite/4MUZ/01/in.yaml new file mode 100644 index 0000000..0ad38e8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/01/in.yaml @@ -0,0 +1,2 @@ +{"foo" +: bar} diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/01/test.event b/Tests/Fixtures/yaml-test-suite/4MUZ/01/test.event new file mode 100644 index 0000000..3552afd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/01/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP {} +=VAL "foo +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/02/in.json b/Tests/Fixtures/yaml-test-suite/4MUZ/02/in.json new file mode 100644 index 0000000..c8c4105 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/02/in.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/02/in.yaml b/Tests/Fixtures/yaml-test-suite/4MUZ/02/in.yaml new file mode 100644 index 0000000..f3b4057 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/02/in.yaml @@ -0,0 +1,2 @@ +{foo +: bar} diff --git a/Tests/Fixtures/yaml-test-suite/4MUZ/02/test.event b/Tests/Fixtures/yaml-test-suite/4MUZ/02/test.event new file mode 100644 index 0000000..dfdf43c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4MUZ/02/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP {} +=VAL :foo +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4Q9F/in.json b/Tests/Fixtures/yaml-test-suite/4Q9F/in.json new file mode 100644 index 0000000..c63e7ba --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4Q9F/in.json @@ -0,0 +1 @@ +"ab cd\nef\n\ngh\n" diff --git a/Tests/Fixtures/yaml-test-suite/4Q9F/in.yaml b/Tests/Fixtures/yaml-test-suite/4Q9F/in.yaml new file mode 100644 index 0000000..63a62ab --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4Q9F/in.yaml @@ -0,0 +1,8 @@ +--- > + ab + cd + + ef + + + gh diff --git a/Tests/Fixtures/yaml-test-suite/4Q9F/test.event b/Tests/Fixtures/yaml-test-suite/4Q9F/test.event new file mode 100644 index 0000000..e01d210 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4Q9F/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL >ab cd\nef\n\ngh\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4QFQ/in.json b/Tests/Fixtures/yaml-test-suite/4QFQ/in.json new file mode 100644 index 0000000..6963db1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4QFQ/in.json @@ -0,0 +1,6 @@ +[ + "detected\n", + "\n\n# detected\n", + " explicit\n", + "detected\n" +] diff --git a/Tests/Fixtures/yaml-test-suite/4QFQ/in.yaml b/Tests/Fixtures/yaml-test-suite/4QFQ/in.yaml new file mode 100644 index 0000000..079de26 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4QFQ/in.yaml @@ -0,0 +1,10 @@ +- | + detected +- > + + + # detected +- |1 + explicit +- > + detected diff --git a/Tests/Fixtures/yaml-test-suite/4QFQ/test.event b/Tests/Fixtures/yaml-test-suite/4QFQ/test.event new file mode 100644 index 0000000..6395611 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4QFQ/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ +=VAL |detected\n +=VAL >\n\n# detected\n +=VAL | explicit\n +=VAL >detected\n +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4RWC/in.json b/Tests/Fixtures/yaml-test-suite/4RWC/in.json new file mode 100644 index 0000000..a85b7c9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4RWC/in.json @@ -0,0 +1,5 @@ +[ + 1, + 2, + 3 +] diff --git a/Tests/Fixtures/yaml-test-suite/4RWC/in.yaml b/Tests/Fixtures/yaml-test-suite/4RWC/in.yaml new file mode 100644 index 0000000..4337a64 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4RWC/in.yaml @@ -0,0 +1,2 @@ + [1, 2, 3] + \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/4RWC/test.event b/Tests/Fixtures/yaml-test-suite/4RWC/test.event new file mode 100644 index 0000000..e4ac376 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4RWC/test.event @@ -0,0 +1,9 @@ ++STR ++DOC ++SEQ [] +=VAL :1 +=VAL :2 +=VAL :3 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4UYU/in.json b/Tests/Fixtures/yaml-test-suite/4UYU/in.json new file mode 100644 index 0000000..912727e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4UYU/in.json @@ -0,0 +1 @@ +"foo: bar\": baz" diff --git a/Tests/Fixtures/yaml-test-suite/4UYU/in.yaml b/Tests/Fixtures/yaml-test-suite/4UYU/in.yaml new file mode 100644 index 0000000..912727e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4UYU/in.yaml @@ -0,0 +1 @@ +"foo: bar\": baz" diff --git a/Tests/Fixtures/yaml-test-suite/4UYU/test.event b/Tests/Fixtures/yaml-test-suite/4UYU/test.event new file mode 100644 index 0000000..f3676a7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4UYU/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "foo: bar": baz +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4V8U/in.json b/Tests/Fixtures/yaml-test-suite/4V8U/in.json new file mode 100644 index 0000000..8391b93 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4V8U/in.json @@ -0,0 +1 @@ +"plain\\value\\with\\backslashes" diff --git a/Tests/Fixtures/yaml-test-suite/4V8U/in.yaml b/Tests/Fixtures/yaml-test-suite/4V8U/in.yaml new file mode 100644 index 0000000..9a786b3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4V8U/in.yaml @@ -0,0 +1,2 @@ +--- +plain\value\with\backslashes diff --git a/Tests/Fixtures/yaml-test-suite/4V8U/test.event b/Tests/Fixtures/yaml-test-suite/4V8U/test.event new file mode 100644 index 0000000..9d7d9dd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4V8U/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :plain\\value\\with\\backslashes +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4WA9/in.json b/Tests/Fixtures/yaml-test-suite/4WA9/in.json new file mode 100644 index 0000000..bc81564 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4WA9/in.json @@ -0,0 +1,6 @@ +[ + { + "aaa" : "xxx\n", + "bbb" : "xxx\n" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/4WA9/in.yaml b/Tests/Fixtures/yaml-test-suite/4WA9/in.yaml new file mode 100644 index 0000000..0d9917e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4WA9/in.yaml @@ -0,0 +1,4 @@ +- aaa: |2 + xxx + bbb: | + xxx diff --git a/Tests/Fixtures/yaml-test-suite/4WA9/test.event b/Tests/Fixtures/yaml-test-suite/4WA9/test.event new file mode 100644 index 0000000..f73c27a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4WA9/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++SEQ ++MAP +=VAL :aaa +=VAL |xxx\n +=VAL :bbb +=VAL |xxx\n +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/4ZYM/in.json b/Tests/Fixtures/yaml-test-suite/4ZYM/in.json new file mode 100644 index 0000000..b90f107 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4ZYM/in.json @@ -0,0 +1,5 @@ +{ + "plain": "text lines", + "quoted": "text lines", + "block": "text\n \tlines\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/4ZYM/in.yaml b/Tests/Fixtures/yaml-test-suite/4ZYM/in.yaml new file mode 100644 index 0000000..2f62d08 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4ZYM/in.yaml @@ -0,0 +1,7 @@ +plain: text + lines +quoted: "text + lines" +block: | + text + lines diff --git a/Tests/Fixtures/yaml-test-suite/4ZYM/test.event b/Tests/Fixtures/yaml-test-suite/4ZYM/test.event new file mode 100644 index 0000000..5bd005b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/4ZYM/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :plain +=VAL :text lines +=VAL :quoted +=VAL "text lines +=VAL :block +=VAL |text\n \tlines\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/52DL/in.json b/Tests/Fixtures/yaml-test-suite/52DL/in.json new file mode 100644 index 0000000..231f150 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/52DL/in.json @@ -0,0 +1 @@ +"a" diff --git a/Tests/Fixtures/yaml-test-suite/52DL/in.yaml b/Tests/Fixtures/yaml-test-suite/52DL/in.yaml new file mode 100644 index 0000000..ed7ee4e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/52DL/in.yaml @@ -0,0 +1,2 @@ +--- +! a diff --git a/Tests/Fixtures/yaml-test-suite/52DL/test.event b/Tests/Fixtures/yaml-test-suite/52DL/test.event new file mode 100644 index 0000000..e04212e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/52DL/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :a +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/54T7/in.json b/Tests/Fixtures/yaml-test-suite/54T7/in.json new file mode 100644 index 0000000..639f014 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/54T7/in.json @@ -0,0 +1,4 @@ +{ + "foo": "you", + "bar": "far" +} diff --git a/Tests/Fixtures/yaml-test-suite/54T7/in.yaml b/Tests/Fixtures/yaml-test-suite/54T7/in.yaml new file mode 100644 index 0000000..fc448be --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/54T7/in.yaml @@ -0,0 +1 @@ +{foo: you, bar: far} diff --git a/Tests/Fixtures/yaml-test-suite/54T7/test.event b/Tests/Fixtures/yaml-test-suite/54T7/test.event new file mode 100644 index 0000000..4b12db7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/54T7/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP {} +=VAL :foo +=VAL :you +=VAL :bar +=VAL :far +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/55WF/error b/Tests/Fixtures/yaml-test-suite/55WF/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/55WF/in.yaml b/Tests/Fixtures/yaml-test-suite/55WF/in.yaml new file mode 100644 index 0000000..73ef8bc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/55WF/in.yaml @@ -0,0 +1,2 @@ +--- +"\." diff --git a/Tests/Fixtures/yaml-test-suite/55WF/test.event b/Tests/Fixtures/yaml-test-suite/55WF/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/55WF/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/565N/in.json b/Tests/Fixtures/yaml-test-suite/565N/in.json new file mode 100644 index 0000000..4b6d817 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/565N/in.json @@ -0,0 +1,5 @@ +{ + "canonical": "R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=", + "generic": "R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\nOTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\n+f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\nAgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=\n", + "description": "The binary value above is a tiny arrow encoded as a gif image." +} diff --git a/Tests/Fixtures/yaml-test-suite/565N/in.yaml b/Tests/Fixtures/yaml-test-suite/565N/in.yaml new file mode 100644 index 0000000..dcdb16f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/565N/in.yaml @@ -0,0 +1,12 @@ +canonical: !!binary "\ + R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\ + OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\ + +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\ + AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=" +generic: !!binary | + R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 + OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ + +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC + AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= +description: + The binary value above is a tiny arrow encoded as a gif image. diff --git a/Tests/Fixtures/yaml-test-suite/565N/test.event b/Tests/Fixtures/yaml-test-suite/565N/test.event new file mode 100644 index 0000000..72c44bf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/565N/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :canonical +=VAL "R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLCAgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= +=VAL :generic +=VAL |R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\nOTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\n+f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\nAgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=\n +=VAL :description +=VAL :The binary value above is a tiny arrow encoded as a gif image. +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/57H4/in.json b/Tests/Fixtures/yaml-test-suite/57H4/in.json new file mode 100644 index 0000000..ed69b21 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/57H4/in.json @@ -0,0 +1,11 @@ +{ + "sequence": [ + "entry", + [ + "nested" + ] + ], + "mapping": { + "foo": "bar" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/57H4/in.yaml b/Tests/Fixtures/yaml-test-suite/57H4/in.yaml new file mode 100644 index 0000000..5c59669 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/57H4/in.yaml @@ -0,0 +1,6 @@ +sequence: !!seq +- entry +- !!seq + - nested +mapping: !!map + foo: bar diff --git a/Tests/Fixtures/yaml-test-suite/57H4/test.event b/Tests/Fixtures/yaml-test-suite/57H4/test.event new file mode 100644 index 0000000..879772a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/57H4/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++MAP +=VAL :sequence ++SEQ +=VAL :entry ++SEQ +=VAL :nested +-SEQ +-SEQ +=VAL :mapping ++MAP +=VAL :foo +=VAL :bar +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/58MP/in.json b/Tests/Fixtures/yaml-test-suite/58MP/in.json new file mode 100644 index 0000000..a6ef103 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/58MP/in.json @@ -0,0 +1,3 @@ +{ + "x": ":x" +} diff --git a/Tests/Fixtures/yaml-test-suite/58MP/in.yaml b/Tests/Fixtures/yaml-test-suite/58MP/in.yaml new file mode 100644 index 0000000..21d0ff9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/58MP/in.yaml @@ -0,0 +1 @@ +{x: :x} diff --git a/Tests/Fixtures/yaml-test-suite/58MP/test.event b/Tests/Fixtures/yaml-test-suite/58MP/test.event new file mode 100644 index 0000000..a71e008 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/58MP/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP {} +=VAL :x +=VAL ::x +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5BVJ/in.json b/Tests/Fixtures/yaml-test-suite/5BVJ/in.json new file mode 100644 index 0000000..a150c17 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5BVJ/in.json @@ -0,0 +1,4 @@ +{ + "literal": "some\ntext\n", + "folded": "some text\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/5BVJ/in.yaml b/Tests/Fixtures/yaml-test-suite/5BVJ/in.yaml new file mode 100644 index 0000000..934726c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5BVJ/in.yaml @@ -0,0 +1,6 @@ +literal: | + some + text +folded: > + some + text diff --git a/Tests/Fixtures/yaml-test-suite/5BVJ/test.event b/Tests/Fixtures/yaml-test-suite/5BVJ/test.event new file mode 100644 index 0000000..b9ee2ee --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5BVJ/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :literal +=VAL |some\ntext\n +=VAL :folded +=VAL >some text\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5C5M/in.json b/Tests/Fixtures/yaml-test-suite/5C5M/in.json new file mode 100644 index 0000000..b516097 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5C5M/in.json @@ -0,0 +1,10 @@ +[ + { + "one": "two", + "three": "four" + }, + { + "five": "six", + "seven": "eight" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/5C5M/in.yaml b/Tests/Fixtures/yaml-test-suite/5C5M/in.yaml new file mode 100644 index 0000000..0718643 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5C5M/in.yaml @@ -0,0 +1,2 @@ +- { one : two , three: four , } +- {five: six,seven : eight} diff --git a/Tests/Fixtures/yaml-test-suite/5C5M/test.event b/Tests/Fixtures/yaml-test-suite/5C5M/test.event new file mode 100644 index 0000000..ae12fba --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5C5M/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++SEQ ++MAP {} +=VAL :one +=VAL :two +=VAL :three +=VAL :four +-MAP ++MAP {} +=VAL :five +=VAL :six +=VAL :seven +=VAL :eight +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5GBF/in.json b/Tests/Fixtures/yaml-test-suite/5GBF/in.json new file mode 100644 index 0000000..41a96a1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5GBF/in.json @@ -0,0 +1,4 @@ +{ + "Folding": "Empty line\nas a line feed", + "Chomping": "Clipped empty lines\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/5GBF/in.yaml b/Tests/Fixtures/yaml-test-suite/5GBF/in.yaml new file mode 100644 index 0000000..60958d5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5GBF/in.yaml @@ -0,0 +1,8 @@ +Folding: + "Empty line + + as a line feed" +Chomping: | + Clipped empty lines + + diff --git a/Tests/Fixtures/yaml-test-suite/5GBF/test.event b/Tests/Fixtures/yaml-test-suite/5GBF/test.event new file mode 100644 index 0000000..1acf1f8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5GBF/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :Folding +=VAL "Empty line\nas a line feed +=VAL :Chomping +=VAL |Clipped empty lines\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5KJE/in.json b/Tests/Fixtures/yaml-test-suite/5KJE/in.json new file mode 100644 index 0000000..c19c46c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5KJE/in.json @@ -0,0 +1,10 @@ +[ + [ + "one", + "two" + ], + [ + "three", + "four" + ] +] diff --git a/Tests/Fixtures/yaml-test-suite/5KJE/in.yaml b/Tests/Fixtures/yaml-test-suite/5KJE/in.yaml new file mode 100644 index 0000000..cd77480 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5KJE/in.yaml @@ -0,0 +1,2 @@ +- [ one, two, ] +- [three ,four] diff --git a/Tests/Fixtures/yaml-test-suite/5KJE/test.event b/Tests/Fixtures/yaml-test-suite/5KJE/test.event new file mode 100644 index 0000000..131aa45 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5KJE/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++SEQ ++SEQ [] +=VAL :one +=VAL :two +-SEQ ++SEQ [] +=VAL :three +=VAL :four +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5LLU/error b/Tests/Fixtures/yaml-test-suite/5LLU/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/5LLU/in.yaml b/Tests/Fixtures/yaml-test-suite/5LLU/in.yaml new file mode 100644 index 0000000..34d30b1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5LLU/in.yaml @@ -0,0 +1,5 @@ +block scalar: > + + + + invalid diff --git a/Tests/Fixtures/yaml-test-suite/5LLU/test.event b/Tests/Fixtures/yaml-test-suite/5LLU/test.event new file mode 100644 index 0000000..bbe95d7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5LLU/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :block scalar diff --git a/Tests/Fixtures/yaml-test-suite/5MUD/in.json b/Tests/Fixtures/yaml-test-suite/5MUD/in.json new file mode 100644 index 0000000..c8c4105 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5MUD/in.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/5MUD/in.yaml b/Tests/Fixtures/yaml-test-suite/5MUD/in.yaml new file mode 100644 index 0000000..f0a4e3e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5MUD/in.yaml @@ -0,0 +1,3 @@ +--- +{ "foo" + :bar } diff --git a/Tests/Fixtures/yaml-test-suite/5MUD/test.event b/Tests/Fixtures/yaml-test-suite/5MUD/test.event new file mode 100644 index 0000000..fd46afc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5MUD/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP {} +=VAL "foo +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5NYZ/in.json b/Tests/Fixtures/yaml-test-suite/5NYZ/in.json new file mode 100644 index 0000000..7a9e864 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5NYZ/in.json @@ -0,0 +1,3 @@ +{ + "key": "value" +} diff --git a/Tests/Fixtures/yaml-test-suite/5NYZ/in.yaml b/Tests/Fixtures/yaml-test-suite/5NYZ/in.yaml new file mode 100644 index 0000000..9db0912 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5NYZ/in.yaml @@ -0,0 +1,2 @@ +key: # Comment + value diff --git a/Tests/Fixtures/yaml-test-suite/5NYZ/test.event b/Tests/Fixtures/yaml-test-suite/5NYZ/test.event new file mode 100644 index 0000000..4010c9a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5NYZ/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :key +=VAL :value +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5T43/in.json b/Tests/Fixtures/yaml-test-suite/5T43/in.json new file mode 100644 index 0000000..7eb5fce --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5T43/in.json @@ -0,0 +1,8 @@ +[ + { + "key": "value" + }, + { + "key": ":value" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/5T43/in.yaml b/Tests/Fixtures/yaml-test-suite/5T43/in.yaml new file mode 100644 index 0000000..03936e6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5T43/in.yaml @@ -0,0 +1,2 @@ +- { "key":value } +- { "key"::value } diff --git a/Tests/Fixtures/yaml-test-suite/5T43/test.event b/Tests/Fixtures/yaml-test-suite/5T43/test.event new file mode 100644 index 0000000..129c059 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5T43/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++SEQ ++MAP {} +=VAL "key +=VAL :value +-MAP ++MAP {} +=VAL "key +=VAL ::value +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5TRB/error b/Tests/Fixtures/yaml-test-suite/5TRB/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/5TRB/in.yaml b/Tests/Fixtures/yaml-test-suite/5TRB/in.yaml new file mode 100644 index 0000000..8f75f6c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5TRB/in.yaml @@ -0,0 +1,4 @@ +--- +" +--- +" diff --git a/Tests/Fixtures/yaml-test-suite/5TRB/test.event b/Tests/Fixtures/yaml-test-suite/5TRB/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5TRB/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/5TYM/in.json b/Tests/Fixtures/yaml-test-suite/5TYM/in.json new file mode 100644 index 0000000..fbdf5d0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5TYM/in.json @@ -0,0 +1,2 @@ +"fluorescent" +"green" diff --git a/Tests/Fixtures/yaml-test-suite/5TYM/in.yaml b/Tests/Fixtures/yaml-test-suite/5TYM/in.yaml new file mode 100644 index 0000000..57315a5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5TYM/in.yaml @@ -0,0 +1,7 @@ +%TAG !m! !my- +--- # Bulb here +!m!light fluorescent +... +%TAG !m! !my- +--- # Color here +!m!light green diff --git a/Tests/Fixtures/yaml-test-suite/5TYM/test.event b/Tests/Fixtures/yaml-test-suite/5TYM/test.event new file mode 100644 index 0000000..6d8a8bc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5TYM/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- +=VAL :fluorescent +-DOC ... ++DOC --- +=VAL :green +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/5U3A/error b/Tests/Fixtures/yaml-test-suite/5U3A/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/5U3A/in.yaml b/Tests/Fixtures/yaml-test-suite/5U3A/in.yaml new file mode 100644 index 0000000..fa966bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5U3A/in.yaml @@ -0,0 +1,2 @@ +key: - a + - b diff --git a/Tests/Fixtures/yaml-test-suite/5U3A/test.event b/Tests/Fixtures/yaml-test-suite/5U3A/test.event new file mode 100644 index 0000000..174e371 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5U3A/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :key diff --git a/Tests/Fixtures/yaml-test-suite/5WE3/in.json b/Tests/Fixtures/yaml-test-suite/5WE3/in.json new file mode 100644 index 0000000..35361a5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5WE3/in.json @@ -0,0 +1,7 @@ +{ + "explicit key": null, + "block key\n": [ + "one", + "two" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/5WE3/in.yaml b/Tests/Fixtures/yaml-test-suite/5WE3/in.yaml new file mode 100644 index 0000000..cb0cfd0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5WE3/in.yaml @@ -0,0 +1,5 @@ +? explicit key # Empty value +? | + block key +: - one # Explicit compact + - two # block value diff --git a/Tests/Fixtures/yaml-test-suite/5WE3/test.event b/Tests/Fixtures/yaml-test-suite/5WE3/test.event new file mode 100644 index 0000000..6bcbc08 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/5WE3/test.event @@ -0,0 +1,13 @@ ++STR ++DOC ++MAP +=VAL :explicit key +=VAL : +=VAL |block key\n ++SEQ +=VAL :one +=VAL :two +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/62EZ/error b/Tests/Fixtures/yaml-test-suite/62EZ/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/62EZ/in.yaml b/Tests/Fixtures/yaml-test-suite/62EZ/in.yaml new file mode 100644 index 0000000..c3bd6ba --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/62EZ/in.yaml @@ -0,0 +1,2 @@ +--- +x: { y: z }in: valid diff --git a/Tests/Fixtures/yaml-test-suite/62EZ/test.event b/Tests/Fixtures/yaml-test-suite/62EZ/test.event new file mode 100644 index 0000000..7723a2b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/62EZ/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :x ++MAP {} +=VAL :y +=VAL :z +-MAP diff --git a/Tests/Fixtures/yaml-test-suite/652Z/in.json b/Tests/Fixtures/yaml-test-suite/652Z/in.json new file mode 100644 index 0000000..5943efa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/652Z/in.json @@ -0,0 +1,4 @@ +{ + "?foo" : "bar", + "bar" : 42 +} diff --git a/Tests/Fixtures/yaml-test-suite/652Z/in.yaml b/Tests/Fixtures/yaml-test-suite/652Z/in.yaml new file mode 100644 index 0000000..c1a9c38 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/652Z/in.yaml @@ -0,0 +1,3 @@ +{ ?foo: bar, +bar: 42 +} diff --git a/Tests/Fixtures/yaml-test-suite/652Z/test.event b/Tests/Fixtures/yaml-test-suite/652Z/test.event new file mode 100644 index 0000000..ff6931a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/652Z/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP {} +=VAL :?foo +=VAL :bar +=VAL :bar +=VAL :42 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/65WH/in.json b/Tests/Fixtures/yaml-test-suite/65WH/in.json new file mode 100644 index 0000000..de140ba --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/65WH/in.json @@ -0,0 +1,3 @@ +[ + "foo" +] diff --git a/Tests/Fixtures/yaml-test-suite/65WH/in.yaml b/Tests/Fixtures/yaml-test-suite/65WH/in.yaml new file mode 100644 index 0000000..a4b65cd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/65WH/in.yaml @@ -0,0 +1 @@ +- foo diff --git a/Tests/Fixtures/yaml-test-suite/65WH/test.event b/Tests/Fixtures/yaml-test-suite/65WH/test.event new file mode 100644 index 0000000..5fd23da --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/65WH/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ +=VAL :foo +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6BCT/in.json b/Tests/Fixtures/yaml-test-suite/6BCT/in.json new file mode 100644 index 0000000..7216337 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6BCT/in.json @@ -0,0 +1,9 @@ +[ + { + "foo": "bar" + }, + [ + "baz", + "baz" + ] +] diff --git a/Tests/Fixtures/yaml-test-suite/6BCT/in.yaml b/Tests/Fixtures/yaml-test-suite/6BCT/in.yaml new file mode 100644 index 0000000..5f48cf4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6BCT/in.yaml @@ -0,0 +1,3 @@ +- foo: bar +- - baz + - baz diff --git a/Tests/Fixtures/yaml-test-suite/6BCT/test.event b/Tests/Fixtures/yaml-test-suite/6BCT/test.event new file mode 100644 index 0000000..905c43d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6BCT/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++SEQ ++MAP +=VAL :foo +=VAL :bar +-MAP ++SEQ +=VAL :baz +=VAL :baz +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6BFJ/in.yaml b/Tests/Fixtures/yaml-test-suite/6BFJ/in.yaml new file mode 100644 index 0000000..19d1e3e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6BFJ/in.yaml @@ -0,0 +1,3 @@ +--- +&mapping +&key [ &item a, b, c ]: value diff --git a/Tests/Fixtures/yaml-test-suite/6BFJ/test.event b/Tests/Fixtures/yaml-test-suite/6BFJ/test.event new file mode 100644 index 0000000..55211ef --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6BFJ/test.event @@ -0,0 +1,12 @@ ++STR ++DOC --- ++MAP &mapping ++SEQ [] &key +=VAL &item :a +=VAL :b +=VAL :c +-SEQ +=VAL :value +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6CA3/in.json b/Tests/Fixtures/yaml-test-suite/6CA3/in.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6CA3/in.json @@ -0,0 +1 @@ +[] diff --git a/Tests/Fixtures/yaml-test-suite/6CA3/in.yaml b/Tests/Fixtures/yaml-test-suite/6CA3/in.yaml new file mode 100644 index 0000000..26a80a6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6CA3/in.yaml @@ -0,0 +1,2 @@ + [ + ] diff --git a/Tests/Fixtures/yaml-test-suite/6CA3/test.event b/Tests/Fixtures/yaml-test-suite/6CA3/test.event new file mode 100644 index 0000000..8163607 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6CA3/test.event @@ -0,0 +1,6 @@ ++STR ++DOC ++SEQ [] +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6CK3/in.json b/Tests/Fixtures/yaml-test-suite/6CK3/in.json new file mode 100644 index 0000000..cdaf9b8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6CK3/in.json @@ -0,0 +1,5 @@ +[ + "foo", + "bar", + "baz" +] diff --git a/Tests/Fixtures/yaml-test-suite/6CK3/in.yaml b/Tests/Fixtures/yaml-test-suite/6CK3/in.yaml new file mode 100644 index 0000000..70365f4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6CK3/in.yaml @@ -0,0 +1,5 @@ +%TAG !e! tag:example.com,2000:app/ +--- +- !local foo +- !!str bar +- !e!tag%21 baz diff --git a/Tests/Fixtures/yaml-test-suite/6CK3/test.event b/Tests/Fixtures/yaml-test-suite/6CK3/test.event new file mode 100644 index 0000000..871fae1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6CK3/test.event @@ -0,0 +1,9 @@ ++STR ++DOC --- ++SEQ +=VAL :foo +=VAL :bar +=VAL :baz +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6FWR/in.json b/Tests/Fixtures/yaml-test-suite/6FWR/in.json new file mode 100644 index 0000000..7b0aa63 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6FWR/in.json @@ -0,0 +1 @@ +"ab\n\n \n" diff --git a/Tests/Fixtures/yaml-test-suite/6FWR/in.yaml b/Tests/Fixtures/yaml-test-suite/6FWR/in.yaml new file mode 100644 index 0000000..1ff9bfa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6FWR/in.yaml @@ -0,0 +1,5 @@ +--- |+ + ab + + +... diff --git a/Tests/Fixtures/yaml-test-suite/6FWR/test.event b/Tests/Fixtures/yaml-test-suite/6FWR/test.event new file mode 100644 index 0000000..69493d9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6FWR/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL |ab\n\n \n +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6H3V/in.json b/Tests/Fixtures/yaml-test-suite/6H3V/in.json new file mode 100644 index 0000000..030ae9c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6H3V/in.json @@ -0,0 +1,3 @@ +{ + "foo: bar\\": "baz'" +} diff --git a/Tests/Fixtures/yaml-test-suite/6H3V/in.yaml b/Tests/Fixtures/yaml-test-suite/6H3V/in.yaml new file mode 100644 index 0000000..33424c0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6H3V/in.yaml @@ -0,0 +1 @@ +'foo: bar\': baz' diff --git a/Tests/Fixtures/yaml-test-suite/6H3V/test.event b/Tests/Fixtures/yaml-test-suite/6H3V/test.event new file mode 100644 index 0000000..b7083c4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6H3V/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL 'foo: bar\\ +=VAL :baz' +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6HB6/in.json b/Tests/Fixtures/yaml-test-suite/6HB6/in.json new file mode 100644 index 0000000..90112cb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6HB6/in.json @@ -0,0 +1,10 @@ +{ + "Not indented": { + "By one space": "By four\n spaces\n", + "Flow style": [ + "By two", + "Also by two", + "Still by two" + ] + } +} diff --git a/Tests/Fixtures/yaml-test-suite/6HB6/in.yaml b/Tests/Fixtures/yaml-test-suite/6HB6/in.yaml new file mode 100644 index 0000000..b5496c1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6HB6/in.yaml @@ -0,0 +1,12 @@ + # Leading comment line spaces are + # neither content nor indentation. + +Not indented: + By one space: | + By four + spaces + Flow style: [ # Leading spaces + By two, # in flow style + Also by two, # are neither + Still by two # content nor + ] # indentation. diff --git a/Tests/Fixtures/yaml-test-suite/6HB6/test.event b/Tests/Fixtures/yaml-test-suite/6HB6/test.event new file mode 100644 index 0000000..73b9865 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6HB6/test.event @@ -0,0 +1,17 @@ ++STR ++DOC ++MAP +=VAL :Not indented ++MAP +=VAL :By one space +=VAL |By four\n spaces\n +=VAL :Flow style ++SEQ [] +=VAL :By two +=VAL :Also by two +=VAL :Still by two +-SEQ +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6JQW/in.json b/Tests/Fixtures/yaml-test-suite/6JQW/in.json new file mode 100644 index 0000000..6f981a5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JQW/in.json @@ -0,0 +1 @@ +"\\//||\\/||\n// || ||__\n" diff --git a/Tests/Fixtures/yaml-test-suite/6JQW/in.yaml b/Tests/Fixtures/yaml-test-suite/6JQW/in.yaml new file mode 100644 index 0000000..13fb656 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JQW/in.yaml @@ -0,0 +1,4 @@ +# ASCII Art +--- | + \//||\/|| + // || ||__ diff --git a/Tests/Fixtures/yaml-test-suite/6JQW/test.event b/Tests/Fixtures/yaml-test-suite/6JQW/test.event new file mode 100644 index 0000000..af5f009 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JQW/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL |\\//||\\/||\n// || ||__\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6JTT/error b/Tests/Fixtures/yaml-test-suite/6JTT/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/6JTT/in.yaml b/Tests/Fixtures/yaml-test-suite/6JTT/in.yaml new file mode 100644 index 0000000..939a071 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JTT/in.yaml @@ -0,0 +1,2 @@ +--- +[ [ a, b, c ] diff --git a/Tests/Fixtures/yaml-test-suite/6JTT/test.event b/Tests/Fixtures/yaml-test-suite/6JTT/test.event new file mode 100644 index 0000000..cd01743 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JTT/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++SEQ [] ++SEQ [] +=VAL :a +=VAL :b +=VAL :c +-SEQ diff --git a/Tests/Fixtures/yaml-test-suite/6JWB/in.json b/Tests/Fixtures/yaml-test-suite/6JWB/in.json new file mode 100644 index 0000000..7f20946 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JWB/in.json @@ -0,0 +1,8 @@ +{ + "foo": [ + "a", + { + "key": "value" + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/6JWB/in.yaml b/Tests/Fixtures/yaml-test-suite/6JWB/in.yaml new file mode 100644 index 0000000..7a3e8f1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JWB/in.yaml @@ -0,0 +1,4 @@ +foo: !!seq + - !!str a + - !!map + key: !!str value diff --git a/Tests/Fixtures/yaml-test-suite/6JWB/test.event b/Tests/Fixtures/yaml-test-suite/6JWB/test.event new file mode 100644 index 0000000..935d250 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6JWB/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :foo ++SEQ +=VAL :a ++MAP +=VAL :key +=VAL :value +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6KGN/in.json b/Tests/Fixtures/yaml-test-suite/6KGN/in.json new file mode 100644 index 0000000..32b9bb5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6KGN/in.json @@ -0,0 +1,4 @@ +{ + "a": null, + "b": null +} diff --git a/Tests/Fixtures/yaml-test-suite/6KGN/in.yaml b/Tests/Fixtures/yaml-test-suite/6KGN/in.yaml new file mode 100644 index 0000000..dea985e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6KGN/in.yaml @@ -0,0 +1,3 @@ +--- +a: &anchor +b: *anchor diff --git a/Tests/Fixtures/yaml-test-suite/6KGN/test.event b/Tests/Fixtures/yaml-test-suite/6KGN/test.event new file mode 100644 index 0000000..a72faa1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6KGN/test.event @@ -0,0 +1,10 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL &anchor : +=VAL :b +=ALI *anchor +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6LVF/in.json b/Tests/Fixtures/yaml-test-suite/6LVF/in.json new file mode 100644 index 0000000..810c96e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6LVF/in.json @@ -0,0 +1 @@ +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/6LVF/in.yaml b/Tests/Fixtures/yaml-test-suite/6LVF/in.yaml new file mode 100644 index 0000000..cedbf23 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6LVF/in.yaml @@ -0,0 +1,3 @@ +%FOO bar baz # Should be ignored + # with a warning. +--- "foo" diff --git a/Tests/Fixtures/yaml-test-suite/6LVF/test.event b/Tests/Fixtures/yaml-test-suite/6LVF/test.event new file mode 100644 index 0000000..324d096 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6LVF/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL "foo +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6M2F/in.yaml b/Tests/Fixtures/yaml-test-suite/6M2F/in.yaml new file mode 100644 index 0000000..b1490a6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6M2F/in.yaml @@ -0,0 +1,3 @@ +? &a a +: &b b +: *a diff --git a/Tests/Fixtures/yaml-test-suite/6M2F/test.event b/Tests/Fixtures/yaml-test-suite/6M2F/test.event new file mode 100644 index 0000000..9e45ad0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6M2F/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL &a :a +=VAL &b :b +=VAL : +=ALI *a +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6PBE/in.yaml b/Tests/Fixtures/yaml-test-suite/6PBE/in.yaml new file mode 100644 index 0000000..5637a1a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6PBE/in.yaml @@ -0,0 +1,7 @@ +--- +? +- a +- b +: +- c +- d diff --git a/Tests/Fixtures/yaml-test-suite/6PBE/test.event b/Tests/Fixtures/yaml-test-suite/6PBE/test.event new file mode 100644 index 0000000..f8fbe17 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6PBE/test.event @@ -0,0 +1,14 @@ ++STR ++DOC --- ++MAP ++SEQ +=VAL :a +=VAL :b +-SEQ ++SEQ +=VAL :c +=VAL :d +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6S55/error b/Tests/Fixtures/yaml-test-suite/6S55/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/6S55/in.yaml b/Tests/Fixtures/yaml-test-suite/6S55/in.yaml new file mode 100644 index 0000000..0b067d6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6S55/in.yaml @@ -0,0 +1,4 @@ +key: + - bar + - baz + invalid diff --git a/Tests/Fixtures/yaml-test-suite/6S55/test.event b/Tests/Fixtures/yaml-test-suite/6S55/test.event new file mode 100644 index 0000000..1df0f42 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6S55/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++MAP +=VAL :key ++SEQ +=VAL :bar +=VAL :baz diff --git a/Tests/Fixtures/yaml-test-suite/6SLA/in.json b/Tests/Fixtures/yaml-test-suite/6SLA/in.json new file mode 100644 index 0000000..b76510f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6SLA/in.json @@ -0,0 +1,4 @@ +{ + "foo\nbar:baz\tx \\$%^&*()x": 23, + "x\\ny:z\\tx $%^&*()x": 24 +} diff --git a/Tests/Fixtures/yaml-test-suite/6SLA/in.yaml b/Tests/Fixtures/yaml-test-suite/6SLA/in.yaml new file mode 100644 index 0000000..5b8cd26 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6SLA/in.yaml @@ -0,0 +1,2 @@ +"foo\nbar:baz\tx \\$%^&*()x": 23 +'x\ny:z\tx $%^&*()x': 24 diff --git a/Tests/Fixtures/yaml-test-suite/6SLA/test.event b/Tests/Fixtures/yaml-test-suite/6SLA/test.event new file mode 100644 index 0000000..9411e77 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6SLA/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL "foo\nbar:baz\tx \\$%^&*()x +=VAL :23 +=VAL 'x\\ny:z\\tx $%^&*()x +=VAL :24 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6VJK/in.json b/Tests/Fixtures/yaml-test-suite/6VJK/in.json new file mode 100644 index 0000000..d61c429 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6VJK/in.json @@ -0,0 +1 @@ +"Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n" diff --git a/Tests/Fixtures/yaml-test-suite/6VJK/in.yaml b/Tests/Fixtures/yaml-test-suite/6VJK/in.yaml new file mode 100644 index 0000000..80b89a6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6VJK/in.yaml @@ -0,0 +1,8 @@ +> + Sammy Sosa completed another + fine season with great stats. + + 63 Home Runs + 0.288 Batting Average + + What a year! diff --git a/Tests/Fixtures/yaml-test-suite/6VJK/test.event b/Tests/Fixtures/yaml-test-suite/6VJK/test.event new file mode 100644 index 0000000..93b252d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6VJK/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL >Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6WLZ/in.json b/Tests/Fixtures/yaml-test-suite/6WLZ/in.json new file mode 100644 index 0000000..f95cbd7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6WLZ/in.json @@ -0,0 +1,2 @@ +"bar" +"bar" diff --git a/Tests/Fixtures/yaml-test-suite/6WLZ/in.yaml b/Tests/Fixtures/yaml-test-suite/6WLZ/in.yaml new file mode 100644 index 0000000..fd94164 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6WLZ/in.yaml @@ -0,0 +1,8 @@ +# Private +--- +!foo "bar" +... +# Global +%TAG ! tag:example.com,2000:app/ +--- +!foo "bar" diff --git a/Tests/Fixtures/yaml-test-suite/6WLZ/test.event b/Tests/Fixtures/yaml-test-suite/6WLZ/test.event new file mode 100644 index 0000000..7730f21 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6WLZ/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- +=VAL "bar +-DOC ... ++DOC --- +=VAL "bar +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6WPF/in.json b/Tests/Fixtures/yaml-test-suite/6WPF/in.json new file mode 100644 index 0000000..0fcc9db --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6WPF/in.json @@ -0,0 +1 @@ +" foo\nbar\nbaz " diff --git a/Tests/Fixtures/yaml-test-suite/6WPF/in.yaml b/Tests/Fixtures/yaml-test-suite/6WPF/in.yaml new file mode 100644 index 0000000..aed6e4b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6WPF/in.yaml @@ -0,0 +1,8 @@ +--- +" + foo + + bar + + baz +" diff --git a/Tests/Fixtures/yaml-test-suite/6WPF/test.event b/Tests/Fixtures/yaml-test-suite/6WPF/test.event new file mode 100644 index 0000000..de0c0ba --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6WPF/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL " foo\nbar\nbaz +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6XDY/in.json b/Tests/Fixtures/yaml-test-suite/6XDY/in.json new file mode 100644 index 0000000..c1e4b6c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6XDY/in.json @@ -0,0 +1,2 @@ +null +null diff --git a/Tests/Fixtures/yaml-test-suite/6XDY/in.yaml b/Tests/Fixtures/yaml-test-suite/6XDY/in.yaml new file mode 100644 index 0000000..a845151 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6XDY/in.yaml @@ -0,0 +1,2 @@ +--- +--- diff --git a/Tests/Fixtures/yaml-test-suite/6XDY/test.event b/Tests/Fixtures/yaml-test-suite/6XDY/test.event new file mode 100644 index 0000000..fe39bfe --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6XDY/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- +=VAL : +-DOC ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/6ZKB/in.json b/Tests/Fixtures/yaml-test-suite/6ZKB/in.json new file mode 100644 index 0000000..b637cb9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6ZKB/in.json @@ -0,0 +1,5 @@ +"Document" +null +{ + "matches %": 20 +} diff --git a/Tests/Fixtures/yaml-test-suite/6ZKB/in.yaml b/Tests/Fixtures/yaml-test-suite/6ZKB/in.yaml new file mode 100644 index 0000000..52bd345 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6ZKB/in.yaml @@ -0,0 +1,7 @@ +Document +--- +# Empty +... +%YAML 1.2 +--- +matches %: 20 diff --git a/Tests/Fixtures/yaml-test-suite/6ZKB/test.event b/Tests/Fixtures/yaml-test-suite/6ZKB/test.event new file mode 100644 index 0000000..3d3b733 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/6ZKB/test.event @@ -0,0 +1,14 @@ ++STR ++DOC +=VAL :Document +-DOC ++DOC --- +=VAL : +-DOC ... ++DOC --- ++MAP +=VAL :matches % +=VAL :20 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/735Y/in.json b/Tests/Fixtures/yaml-test-suite/735Y/in.json new file mode 100644 index 0000000..0cca491 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/735Y/in.json @@ -0,0 +1,7 @@ +[ + "flow in block", + "Block scalar\n", + { + "foo": "bar" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/735Y/in.yaml b/Tests/Fixtures/yaml-test-suite/735Y/in.yaml new file mode 100644 index 0000000..a3f13ae --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/735Y/in.yaml @@ -0,0 +1,6 @@ +- + "flow in block" +- > + Block scalar +- !!map # Block collection + foo : bar diff --git a/Tests/Fixtures/yaml-test-suite/735Y/test.event b/Tests/Fixtures/yaml-test-suite/735Y/test.event new file mode 100644 index 0000000..0636edf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/735Y/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++SEQ +=VAL "flow in block +=VAL >Block scalar\n ++MAP +=VAL :foo +=VAL :bar +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/74H7/in.json b/Tests/Fixtures/yaml-test-suite/74H7/in.json new file mode 100644 index 0000000..5890c51 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/74H7/in.json @@ -0,0 +1,7 @@ +{ + "a": "b", + "c": 42, + "e": "f", + "g": "h", + "23": false +} diff --git a/Tests/Fixtures/yaml-test-suite/74H7/in.yaml b/Tests/Fixtures/yaml-test-suite/74H7/in.yaml new file mode 100644 index 0000000..dd1a8fa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/74H7/in.yaml @@ -0,0 +1,5 @@ +!!str a: b +c: !!int 42 +e: !!str f +g: h +!!str 23: !!bool false diff --git a/Tests/Fixtures/yaml-test-suite/74H7/test.event b/Tests/Fixtures/yaml-test-suite/74H7/test.event new file mode 100644 index 0000000..1f20e00 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/74H7/test.event @@ -0,0 +1,16 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL :b +=VAL :c +=VAL :42 +=VAL :e +=VAL :f +=VAL :g +=VAL :h +=VAL :23 +=VAL :false +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/753E/in.json b/Tests/Fixtures/yaml-test-suite/753E/in.json new file mode 100644 index 0000000..cb5537d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/753E/in.json @@ -0,0 +1 @@ +"ab" diff --git a/Tests/Fixtures/yaml-test-suite/753E/in.yaml b/Tests/Fixtures/yaml-test-suite/753E/in.yaml new file mode 100644 index 0000000..33a6577 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/753E/in.yaml @@ -0,0 +1,5 @@ +--- |- + ab + + +... diff --git a/Tests/Fixtures/yaml-test-suite/753E/test.event b/Tests/Fixtures/yaml-test-suite/753E/test.event new file mode 100644 index 0000000..292efb4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/753E/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL |ab +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7A4E/in.json b/Tests/Fixtures/yaml-test-suite/7A4E/in.json new file mode 100644 index 0000000..2dfab84 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7A4E/in.json @@ -0,0 +1 @@ +" 1st non-empty\n2nd non-empty 3rd non-empty " diff --git a/Tests/Fixtures/yaml-test-suite/7A4E/in.yaml b/Tests/Fixtures/yaml-test-suite/7A4E/in.yaml new file mode 100644 index 0000000..3d8b76d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7A4E/in.yaml @@ -0,0 +1,4 @@ +" 1st non-empty + + 2nd non-empty + 3rd non-empty " diff --git a/Tests/Fixtures/yaml-test-suite/7A4E/test.event b/Tests/Fixtures/yaml-test-suite/7A4E/test.event new file mode 100644 index 0000000..c831930 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7A4E/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL " 1st non-empty\n2nd non-empty 3rd non-empty +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7BMT/in.json b/Tests/Fixtures/yaml-test-suite/7BMT/in.json new file mode 100644 index 0000000..7bc2e58 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7BMT/in.json @@ -0,0 +1,19 @@ +{ + "top1": { + "key1": "one" + }, + "top2": { + "key2": "two" + }, + "top3": { + "key3": "three" + }, + "top4": { + "key4": "four" + }, + "top5": { + "key5": "five" + }, + "top6": "six", + "top7": "seven" +} diff --git a/Tests/Fixtures/yaml-test-suite/7BMT/in.yaml b/Tests/Fixtures/yaml-test-suite/7BMT/in.yaml new file mode 100644 index 0000000..6d66011 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7BMT/in.yaml @@ -0,0 +1,15 @@ +--- +top1: &node1 + &k1 key1: one +top2: &node2 # comment + key2: two +top3: + &k3 key3: three +top4: &node4 + &k4 key4: four +top5: &node5 + key5: five +top6: &val6 + six +top7: + &val7 seven diff --git a/Tests/Fixtures/yaml-test-suite/7BMT/test.event b/Tests/Fixtures/yaml-test-suite/7BMT/test.event new file mode 100644 index 0000000..4b924ae --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7BMT/test.event @@ -0,0 +1,35 @@ ++STR ++DOC --- ++MAP +=VAL :top1 ++MAP &node1 +=VAL &k1 :key1 +=VAL :one +-MAP +=VAL :top2 ++MAP &node2 +=VAL :key2 +=VAL :two +-MAP +=VAL :top3 ++MAP +=VAL &k3 :key3 +=VAL :three +-MAP +=VAL :top4 ++MAP &node4 +=VAL &k4 :key4 +=VAL :four +-MAP +=VAL :top5 ++MAP &node5 +=VAL :key5 +=VAL :five +-MAP +=VAL :top6 +=VAL &val6 :six +=VAL :top7 +=VAL &val7 :seven +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7BUB/in.json b/Tests/Fixtures/yaml-test-suite/7BUB/in.json new file mode 100644 index 0000000..d32dc2f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7BUB/in.json @@ -0,0 +1,10 @@ +{ + "hr": [ + "Mark McGwire", + "Sammy Sosa" + ], + "rbi": [ + "Sammy Sosa", + "Ken Griffey" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/7BUB/in.yaml b/Tests/Fixtures/yaml-test-suite/7BUB/in.yaml new file mode 100644 index 0000000..61808f6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7BUB/in.yaml @@ -0,0 +1,8 @@ +--- +hr: + - Mark McGwire + # Following node labeled SS + - &SS Sammy Sosa +rbi: + - *SS # Subsequent occurrence + - Ken Griffey diff --git a/Tests/Fixtures/yaml-test-suite/7BUB/test.event b/Tests/Fixtures/yaml-test-suite/7BUB/test.event new file mode 100644 index 0000000..0dcba44 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7BUB/test.event @@ -0,0 +1,16 @@ ++STR ++DOC --- ++MAP +=VAL :hr ++SEQ +=VAL :Mark McGwire +=VAL &SS :Sammy Sosa +-SEQ +=VAL :rbi ++SEQ +=ALI *SS +=VAL :Ken Griffey +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7FWL/in.json b/Tests/Fixtures/yaml-test-suite/7FWL/in.json new file mode 100644 index 0000000..c9f7a94 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7FWL/in.json @@ -0,0 +1,3 @@ +{ + "foo": "baz" +} diff --git a/Tests/Fixtures/yaml-test-suite/7FWL/in.yaml b/Tests/Fixtures/yaml-test-suite/7FWL/in.yaml new file mode 100644 index 0000000..8e51f52 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7FWL/in.yaml @@ -0,0 +1,2 @@ +! foo : + ! baz diff --git a/Tests/Fixtures/yaml-test-suite/7FWL/test.event b/Tests/Fixtures/yaml-test-suite/7FWL/test.event new file mode 100644 index 0000000..2aeeeed --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7FWL/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :baz +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7LBH/error b/Tests/Fixtures/yaml-test-suite/7LBH/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/7LBH/in.yaml b/Tests/Fixtures/yaml-test-suite/7LBH/in.yaml new file mode 100644 index 0000000..6953d40 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7LBH/in.yaml @@ -0,0 +1,3 @@ +"a\nb": 1 +"c + d": 1 diff --git a/Tests/Fixtures/yaml-test-suite/7LBH/test.event b/Tests/Fixtures/yaml-test-suite/7LBH/test.event new file mode 100644 index 0000000..bc8ff06 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7LBH/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL "a\nb +=VAL :1 diff --git a/Tests/Fixtures/yaml-test-suite/7MNF/error b/Tests/Fixtures/yaml-test-suite/7MNF/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/7MNF/in.yaml b/Tests/Fixtures/yaml-test-suite/7MNF/in.yaml new file mode 100644 index 0000000..39bce10 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7MNF/in.yaml @@ -0,0 +1,3 @@ +top1: + key1: val1 +top2 diff --git a/Tests/Fixtures/yaml-test-suite/7MNF/test.event b/Tests/Fixtures/yaml-test-suite/7MNF/test.event new file mode 100644 index 0000000..816444c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7MNF/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :top1 ++MAP +=VAL :key1 +=VAL :val1 +-MAP diff --git a/Tests/Fixtures/yaml-test-suite/7T8X/in.json b/Tests/Fixtures/yaml-test-suite/7T8X/in.json new file mode 100644 index 0000000..f52f875 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7T8X/in.json @@ -0,0 +1 @@ +"\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n" diff --git a/Tests/Fixtures/yaml-test-suite/7T8X/in.yaml b/Tests/Fixtures/yaml-test-suite/7T8X/in.yaml new file mode 100644 index 0000000..992dd76 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7T8X/in.yaml @@ -0,0 +1,16 @@ +> + + folded + line + + next + line + * bullet + + * list + * lines + + last + line + +# Comment diff --git a/Tests/Fixtures/yaml-test-suite/7T8X/test.event b/Tests/Fixtures/yaml-test-suite/7T8X/test.event new file mode 100644 index 0000000..c6e1829 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7T8X/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL >\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7TMG/in.json b/Tests/Fixtures/yaml-test-suite/7TMG/in.json new file mode 100644 index 0000000..064aca0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7TMG/in.json @@ -0,0 +1,4 @@ +[ + "word1", + "word2" +] diff --git a/Tests/Fixtures/yaml-test-suite/7TMG/in.yaml b/Tests/Fixtures/yaml-test-suite/7TMG/in.yaml new file mode 100644 index 0000000..312847e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7TMG/in.yaml @@ -0,0 +1,4 @@ +--- +[ word1 +# comment +, word2] diff --git a/Tests/Fixtures/yaml-test-suite/7TMG/test.event b/Tests/Fixtures/yaml-test-suite/7TMG/test.event new file mode 100644 index 0000000..67aa08a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7TMG/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++SEQ [] +=VAL :word1 +=VAL :word2 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7W2P/in.json b/Tests/Fixtures/yaml-test-suite/7W2P/in.json new file mode 100644 index 0000000..a08ddaa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7W2P/in.json @@ -0,0 +1,5 @@ +{ + "a": null, + "b": null, + "c": null +} diff --git a/Tests/Fixtures/yaml-test-suite/7W2P/in.yaml b/Tests/Fixtures/yaml-test-suite/7W2P/in.yaml new file mode 100644 index 0000000..e36dcc9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7W2P/in.yaml @@ -0,0 +1,3 @@ +? a +? b +c: diff --git a/Tests/Fixtures/yaml-test-suite/7W2P/test.event b/Tests/Fixtures/yaml-test-suite/7W2P/test.event new file mode 100644 index 0000000..90a6a7b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7W2P/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL : +=VAL :b +=VAL : +=VAL :c +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7Z25/in.json b/Tests/Fixtures/yaml-test-suite/7Z25/in.json new file mode 100644 index 0000000..ca729cd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7Z25/in.json @@ -0,0 +1,4 @@ +"scalar1" +{ + "key": "value" +} diff --git a/Tests/Fixtures/yaml-test-suite/7Z25/in.yaml b/Tests/Fixtures/yaml-test-suite/7Z25/in.yaml new file mode 100644 index 0000000..6964944 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7Z25/in.yaml @@ -0,0 +1,4 @@ +--- +scalar1 +... +key: value diff --git a/Tests/Fixtures/yaml-test-suite/7Z25/test.event b/Tests/Fixtures/yaml-test-suite/7Z25/test.event new file mode 100644 index 0000000..727a5cb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7Z25/test.event @@ -0,0 +1,11 @@ ++STR ++DOC --- +=VAL :scalar1 +-DOC ... ++DOC ++MAP +=VAL :key +=VAL :value +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/7ZZ5/in.json b/Tests/Fixtures/yaml-test-suite/7ZZ5/in.json new file mode 100644 index 0000000..ab44179 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7ZZ5/in.json @@ -0,0 +1,16 @@ +{ + "nested sequences": [ + [ + [ + [] + ] + ], + [ + [ + {} + ] + ] + ], + "key1": [], + "key2": {} +} diff --git a/Tests/Fixtures/yaml-test-suite/7ZZ5/in.yaml b/Tests/Fixtures/yaml-test-suite/7ZZ5/in.yaml new file mode 100644 index 0000000..9f12ef2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7ZZ5/in.yaml @@ -0,0 +1,6 @@ +--- +nested sequences: +- - - [] +- - - {} +key1: [] +key2: {} diff --git a/Tests/Fixtures/yaml-test-suite/7ZZ5/test.event b/Tests/Fixtures/yaml-test-suite/7ZZ5/test.event new file mode 100644 index 0000000..782158e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/7ZZ5/test.event @@ -0,0 +1,27 @@ ++STR ++DOC --- ++MAP +=VAL :nested sequences ++SEQ ++SEQ ++SEQ ++SEQ [] +-SEQ +-SEQ +-SEQ ++SEQ ++SEQ ++MAP {} +-MAP +-SEQ +-SEQ +-SEQ +=VAL :key1 ++SEQ [] +-SEQ +=VAL :key2 ++MAP {} +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/82AN/in.json b/Tests/Fixtures/yaml-test-suite/82AN/in.json new file mode 100644 index 0000000..62a7caa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/82AN/in.json @@ -0,0 +1 @@ +"---word1 word2" diff --git a/Tests/Fixtures/yaml-test-suite/82AN/in.yaml b/Tests/Fixtures/yaml-test-suite/82AN/in.yaml new file mode 100644 index 0000000..fffaf58 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/82AN/in.yaml @@ -0,0 +1,2 @@ +---word1 +word2 diff --git a/Tests/Fixtures/yaml-test-suite/82AN/test.event b/Tests/Fixtures/yaml-test-suite/82AN/test.event new file mode 100644 index 0000000..76bfe86 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/82AN/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL :---word1 word2 +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/87E4/in.json b/Tests/Fixtures/yaml-test-suite/87E4/in.json new file mode 100644 index 0000000..16ae65b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/87E4/in.json @@ -0,0 +1,7 @@ +{ + "implicit block key": [ + { + "implicit flow key": "value" + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/87E4/in.yaml b/Tests/Fixtures/yaml-test-suite/87E4/in.yaml new file mode 100644 index 0000000..f1baf58 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/87E4/in.yaml @@ -0,0 +1,3 @@ +'implicit block key' : [ + 'implicit flow key' : value, + ] diff --git a/Tests/Fixtures/yaml-test-suite/87E4/test.event b/Tests/Fixtures/yaml-test-suite/87E4/test.event new file mode 100644 index 0000000..4dd3d72 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/87E4/test.event @@ -0,0 +1,13 @@ ++STR ++DOC ++MAP +=VAL 'implicit block key ++SEQ [] ++MAP {} +=VAL 'implicit flow key +=VAL :value +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/8CWC/in.json b/Tests/Fixtures/yaml-test-suite/8CWC/in.json new file mode 100644 index 0000000..64ee5f2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8CWC/in.json @@ -0,0 +1,3 @@ +{ + "key ends with two colons::": "value" +} diff --git a/Tests/Fixtures/yaml-test-suite/8CWC/in.yaml b/Tests/Fixtures/yaml-test-suite/8CWC/in.yaml new file mode 100644 index 0000000..79d518d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8CWC/in.yaml @@ -0,0 +1,2 @@ +--- +key ends with two colons::: value diff --git a/Tests/Fixtures/yaml-test-suite/8CWC/test.event b/Tests/Fixtures/yaml-test-suite/8CWC/test.event new file mode 100644 index 0000000..bb16181 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8CWC/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :key ends with two colons:: +=VAL :value +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/8G76/in.json b/Tests/Fixtures/yaml-test-suite/8G76/in.json new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/8G76/in.yaml b/Tests/Fixtures/yaml-test-suite/8G76/in.yaml new file mode 100644 index 0000000..e5f1a84 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8G76/in.yaml @@ -0,0 +1,4 @@ + # Comment + + + diff --git a/Tests/Fixtures/yaml-test-suite/8G76/test.event b/Tests/Fixtures/yaml-test-suite/8G76/test.event new file mode 100644 index 0000000..a8c0574 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8G76/test.event @@ -0,0 +1,2 @@ ++STR +-STR diff --git a/Tests/Fixtures/yaml-test-suite/8KB6/in.json b/Tests/Fixtures/yaml-test-suite/8KB6/in.json new file mode 100644 index 0000000..2716276 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8KB6/in.json @@ -0,0 +1,10 @@ +[ + { + "single line": null, + "a": "b" + }, + { + "multi line": null, + "a": "b" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/8KB6/in.yaml b/Tests/Fixtures/yaml-test-suite/8KB6/in.yaml new file mode 100644 index 0000000..9167fd6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8KB6/in.yaml @@ -0,0 +1,4 @@ +--- +- { single line, a: b} +- { multi + line, a: b} diff --git a/Tests/Fixtures/yaml-test-suite/8KB6/test.event b/Tests/Fixtures/yaml-test-suite/8KB6/test.event new file mode 100644 index 0000000..4c1ebbf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8KB6/test.event @@ -0,0 +1,18 @@ ++STR ++DOC --- ++SEQ ++MAP {} +=VAL :single line +=VAL : +=VAL :a +=VAL :b +-MAP ++MAP {} +=VAL :multi line +=VAL : +=VAL :a +=VAL :b +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/8MK2/in.json b/Tests/Fixtures/yaml-test-suite/8MK2/in.json new file mode 100644 index 0000000..231f150 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8MK2/in.json @@ -0,0 +1 @@ +"a" diff --git a/Tests/Fixtures/yaml-test-suite/8MK2/in.yaml b/Tests/Fixtures/yaml-test-suite/8MK2/in.yaml new file mode 100644 index 0000000..eae54f7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8MK2/in.yaml @@ -0,0 +1 @@ +! a diff --git a/Tests/Fixtures/yaml-test-suite/8MK2/test.event b/Tests/Fixtures/yaml-test-suite/8MK2/test.event new file mode 100644 index 0000000..4ad166a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8MK2/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL :a +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/8QBE/in.json b/Tests/Fixtures/yaml-test-suite/8QBE/in.json new file mode 100644 index 0000000..53a2601 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8QBE/in.json @@ -0,0 +1,6 @@ +{ + "key": [ + "item1", + "item2" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/8QBE/in.yaml b/Tests/Fixtures/yaml-test-suite/8QBE/in.yaml new file mode 100644 index 0000000..6b937f8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8QBE/in.yaml @@ -0,0 +1,3 @@ +key: + - item1 + - item2 diff --git a/Tests/Fixtures/yaml-test-suite/8QBE/test.event b/Tests/Fixtures/yaml-test-suite/8QBE/test.event new file mode 100644 index 0000000..18deb3b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8QBE/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++MAP +=VAL :key ++SEQ +=VAL :item1 +=VAL :item2 +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/8UDB/in.json b/Tests/Fixtures/yaml-test-suite/8UDB/in.json new file mode 100644 index 0000000..763236f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8UDB/in.json @@ -0,0 +1,11 @@ +[ + "double quoted", + "single quoted", + "plain text", + [ + "nested" + ], + { + "single": "pair" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/8UDB/in.yaml b/Tests/Fixtures/yaml-test-suite/8UDB/in.yaml new file mode 100644 index 0000000..6327116 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8UDB/in.yaml @@ -0,0 +1,8 @@ +[ +"double + quoted", 'single + quoted', +plain + text, [ nested ], +single: pair, +] diff --git a/Tests/Fixtures/yaml-test-suite/8UDB/test.event b/Tests/Fixtures/yaml-test-suite/8UDB/test.event new file mode 100644 index 0000000..7378045 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8UDB/test.event @@ -0,0 +1,16 @@ ++STR ++DOC ++SEQ [] +=VAL "double quoted +=VAL 'single quoted +=VAL :plain text ++SEQ [] +=VAL :nested +-SEQ ++MAP {} +=VAL :single +=VAL :pair +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/8XDJ/error b/Tests/Fixtures/yaml-test-suite/8XDJ/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/8XDJ/in.yaml b/Tests/Fixtures/yaml-test-suite/8XDJ/in.yaml new file mode 100644 index 0000000..5045e77 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8XDJ/in.yaml @@ -0,0 +1,3 @@ +key: word1 +# xxx + word2 diff --git a/Tests/Fixtures/yaml-test-suite/8XDJ/test.event b/Tests/Fixtures/yaml-test-suite/8XDJ/test.event new file mode 100644 index 0000000..74316c2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8XDJ/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :key +=VAL :word1 diff --git a/Tests/Fixtures/yaml-test-suite/8XYN/in.json b/Tests/Fixtures/yaml-test-suite/8XYN/in.json new file mode 100644 index 0000000..85f4c1a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8XYN/in.json @@ -0,0 +1,3 @@ +[ + "unicode anchor" +] diff --git a/Tests/Fixtures/yaml-test-suite/8XYN/in.yaml b/Tests/Fixtures/yaml-test-suite/8XYN/in.yaml new file mode 100644 index 0000000..72c1c37 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8XYN/in.yaml @@ -0,0 +1,2 @@ +--- +- &😁 unicode anchor diff --git a/Tests/Fixtures/yaml-test-suite/8XYN/test.event b/Tests/Fixtures/yaml-test-suite/8XYN/test.event new file mode 100644 index 0000000..eeeb858 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/8XYN/test.event @@ -0,0 +1,7 @@ ++STR ++DOC --- ++SEQ +=VAL &😁 :unicode anchor +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/93JH/in.json b/Tests/Fixtures/yaml-test-suite/93JH/in.json new file mode 100644 index 0000000..ab22c39 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/93JH/in.json @@ -0,0 +1,9 @@ +[ + { + "key": "value", + "key2": "value2" + }, + { + "key3": "value3" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/93JH/in.yaml b/Tests/Fixtures/yaml-test-suite/93JH/in.yaml new file mode 100644 index 0000000..30c49a3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/93JH/in.yaml @@ -0,0 +1,4 @@ + - key: value + key2: value2 + - + key3: value3 diff --git a/Tests/Fixtures/yaml-test-suite/93JH/test.event b/Tests/Fixtures/yaml-test-suite/93JH/test.event new file mode 100644 index 0000000..d036a62 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/93JH/test.event @@ -0,0 +1,16 @@ ++STR ++DOC ++SEQ ++MAP +=VAL :key +=VAL :value +=VAL :key2 +=VAL :value2 +-MAP ++MAP +=VAL :key3 +=VAL :value3 +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/93WF/in.json b/Tests/Fixtures/yaml-test-suite/93WF/in.json new file mode 100644 index 0000000..9c6ce92 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/93WF/in.json @@ -0,0 +1 @@ +"trimmed\n\n\nas space" diff --git a/Tests/Fixtures/yaml-test-suite/93WF/in.yaml b/Tests/Fixtures/yaml-test-suite/93WF/in.yaml new file mode 100644 index 0000000..938ee98 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/93WF/in.yaml @@ -0,0 +1,7 @@ +--- >- + trimmed + + + + as + space diff --git a/Tests/Fixtures/yaml-test-suite/93WF/test.event b/Tests/Fixtures/yaml-test-suite/93WF/test.event new file mode 100644 index 0000000..7d16ac3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/93WF/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL >trimmed\n\n\nas space +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/96L6/in.json b/Tests/Fixtures/yaml-test-suite/96L6/in.json new file mode 100644 index 0000000..f427bc2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96L6/in.json @@ -0,0 +1 @@ +"Mark McGwire's year was crippled by a knee injury.\n" diff --git a/Tests/Fixtures/yaml-test-suite/96L6/in.yaml b/Tests/Fixtures/yaml-test-suite/96L6/in.yaml new file mode 100644 index 0000000..fb4ed4a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96L6/in.yaml @@ -0,0 +1,4 @@ +--- > + Mark McGwire's + year was crippled + by a knee injury. diff --git a/Tests/Fixtures/yaml-test-suite/96L6/test.event b/Tests/Fixtures/yaml-test-suite/96L6/test.event new file mode 100644 index 0000000..debe8c0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96L6/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL >Mark McGwire's year was crippled by a knee injury.\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/96NN/00/in.json b/Tests/Fixtures/yaml-test-suite/96NN/00/in.json new file mode 100644 index 0000000..0adc1e5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96NN/00/in.json @@ -0,0 +1 @@ +{"foo":"\tbar"} diff --git a/Tests/Fixtures/yaml-test-suite/96NN/00/in.yaml b/Tests/Fixtures/yaml-test-suite/96NN/00/in.yaml new file mode 100644 index 0000000..de7acab --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96NN/00/in.yaml @@ -0,0 +1,2 @@ +foo: |- + bar diff --git a/Tests/Fixtures/yaml-test-suite/96NN/00/test.event b/Tests/Fixtures/yaml-test-suite/96NN/00/test.event new file mode 100644 index 0000000..0d18bd9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96NN/00/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL |\tbar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/96NN/01/in.json b/Tests/Fixtures/yaml-test-suite/96NN/01/in.json new file mode 100644 index 0000000..0adc1e5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96NN/01/in.json @@ -0,0 +1 @@ +{"foo":"\tbar"} diff --git a/Tests/Fixtures/yaml-test-suite/96NN/01/in.yaml b/Tests/Fixtures/yaml-test-suite/96NN/01/in.yaml new file mode 100644 index 0000000..28703ea --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96NN/01/in.yaml @@ -0,0 +1,2 @@ +foo: |- + bar \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/96NN/01/test.event b/Tests/Fixtures/yaml-test-suite/96NN/01/test.event new file mode 100644 index 0000000..0d18bd9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/96NN/01/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL |\tbar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/98YD/in.json b/Tests/Fixtures/yaml-test-suite/98YD/in.json new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/98YD/in.yaml b/Tests/Fixtures/yaml-test-suite/98YD/in.yaml new file mode 100644 index 0000000..62524c0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/98YD/in.yaml @@ -0,0 +1 @@ +# Comment only. diff --git a/Tests/Fixtures/yaml-test-suite/98YD/test.event b/Tests/Fixtures/yaml-test-suite/98YD/test.event new file mode 100644 index 0000000..a8c0574 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/98YD/test.event @@ -0,0 +1,2 @@ ++STR +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9BXH/in.json b/Tests/Fixtures/yaml-test-suite/9BXH/in.json new file mode 100644 index 0000000..2716276 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9BXH/in.json @@ -0,0 +1,10 @@ +[ + { + "single line": null, + "a": "b" + }, + { + "multi line": null, + "a": "b" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/9BXH/in.yaml b/Tests/Fixtures/yaml-test-suite/9BXH/in.yaml new file mode 100644 index 0000000..c007827 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9BXH/in.yaml @@ -0,0 +1,4 @@ +--- +- { "single line", a: b} +- { "multi + line", a: b} diff --git a/Tests/Fixtures/yaml-test-suite/9BXH/test.event b/Tests/Fixtures/yaml-test-suite/9BXH/test.event new file mode 100644 index 0000000..b61149c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9BXH/test.event @@ -0,0 +1,18 @@ ++STR ++DOC --- ++SEQ ++MAP {} +=VAL "single line +=VAL : +=VAL :a +=VAL :b +-MAP ++MAP {} +=VAL "multi line +=VAL : +=VAL :a +=VAL :b +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9C9N/error b/Tests/Fixtures/yaml-test-suite/9C9N/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9C9N/in.yaml b/Tests/Fixtures/yaml-test-suite/9C9N/in.yaml new file mode 100644 index 0000000..6378c08 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9C9N/in.yaml @@ -0,0 +1,4 @@ +--- +flow: [a, +b, +c] diff --git a/Tests/Fixtures/yaml-test-suite/9C9N/test.event b/Tests/Fixtures/yaml-test-suite/9C9N/test.event new file mode 100644 index 0000000..2a63d35 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9C9N/test.event @@ -0,0 +1,6 @@ ++STR ++DOC --- ++MAP +=VAL :flow ++SEQ [] +=VAL :a diff --git a/Tests/Fixtures/yaml-test-suite/9CWY/error b/Tests/Fixtures/yaml-test-suite/9CWY/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9CWY/in.yaml b/Tests/Fixtures/yaml-test-suite/9CWY/in.yaml new file mode 100644 index 0000000..b84657b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9CWY/in.yaml @@ -0,0 +1,4 @@ +key: + - item1 + - item2 +invalid diff --git a/Tests/Fixtures/yaml-test-suite/9CWY/test.event b/Tests/Fixtures/yaml-test-suite/9CWY/test.event new file mode 100644 index 0000000..152fcfd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9CWY/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :key ++SEQ +=VAL :item1 +=VAL :item2 +-SEQ diff --git a/Tests/Fixtures/yaml-test-suite/9DXL/in.json b/Tests/Fixtures/yaml-test-suite/9DXL/in.json new file mode 100644 index 0000000..e211160 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9DXL/in.json @@ -0,0 +1,7 @@ +{ + "Mapping": "Document" +} +null +{ + "matches %": 20 +} diff --git a/Tests/Fixtures/yaml-test-suite/9DXL/in.yaml b/Tests/Fixtures/yaml-test-suite/9DXL/in.yaml new file mode 100644 index 0000000..7ec08e8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9DXL/in.yaml @@ -0,0 +1,7 @@ +Mapping: Document +--- +# Empty +... +%YAML 1.2 +--- +matches %: 20 diff --git a/Tests/Fixtures/yaml-test-suite/9DXL/test.event b/Tests/Fixtures/yaml-test-suite/9DXL/test.event new file mode 100644 index 0000000..b472f9b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9DXL/test.event @@ -0,0 +1,17 @@ ++STR ++DOC ++MAP +=VAL :Mapping +=VAL :Document +-MAP +-DOC ++DOC --- +=VAL : +-DOC ... ++DOC --- ++MAP +=VAL :matches % +=VAL :20 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9FMG/in.json b/Tests/Fixtures/yaml-test-suite/9FMG/in.json new file mode 100644 index 0000000..b521c7f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9FMG/in.json @@ -0,0 +1,11 @@ +{ + "a": { + "b": { + "c": "d" + }, + "e": { + "f": "g" + } + }, + "h": "i" +} diff --git a/Tests/Fixtures/yaml-test-suite/9FMG/in.yaml b/Tests/Fixtures/yaml-test-suite/9FMG/in.yaml new file mode 100644 index 0000000..25f0447 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9FMG/in.yaml @@ -0,0 +1,6 @@ +a: + b: + c: d + e: + f: g +h: i diff --git a/Tests/Fixtures/yaml-test-suite/9FMG/test.event b/Tests/Fixtures/yaml-test-suite/9FMG/test.event new file mode 100644 index 0000000..0302e1a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9FMG/test.event @@ -0,0 +1,21 @@ ++STR ++DOC ++MAP +=VAL :a ++MAP +=VAL :b ++MAP +=VAL :c +=VAL :d +-MAP +=VAL :e ++MAP +=VAL :f +=VAL :g +-MAP +-MAP +=VAL :h +=VAL :i +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9HCY/error b/Tests/Fixtures/yaml-test-suite/9HCY/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9HCY/in.yaml b/Tests/Fixtures/yaml-test-suite/9HCY/in.yaml new file mode 100644 index 0000000..dc49d9c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9HCY/in.yaml @@ -0,0 +1,4 @@ +!foo "bar" +%TAG ! tag:example.com,2000:app/ +--- +!foo "bar" diff --git a/Tests/Fixtures/yaml-test-suite/9HCY/test.event b/Tests/Fixtures/yaml-test-suite/9HCY/test.event new file mode 100644 index 0000000..83ddec4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9HCY/test.event @@ -0,0 +1,3 @@ ++STR ++DOC +=VAL "bar diff --git a/Tests/Fixtures/yaml-test-suite/9J7A/in.json b/Tests/Fixtures/yaml-test-suite/9J7A/in.json new file mode 100644 index 0000000..faa9156 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9J7A/in.json @@ -0,0 +1,5 @@ +{ + "foo": { + "bar": "baz" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/9J7A/in.yaml b/Tests/Fixtures/yaml-test-suite/9J7A/in.yaml new file mode 100644 index 0000000..4ee8d9d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9J7A/in.yaml @@ -0,0 +1,2 @@ +foo: + bar: baz diff --git a/Tests/Fixtures/yaml-test-suite/9J7A/test.event b/Tests/Fixtures/yaml-test-suite/9J7A/test.event new file mode 100644 index 0000000..2e55ea9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9J7A/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++MAP +=VAL :foo ++MAP +=VAL :bar +=VAL :baz +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9JBA/error b/Tests/Fixtures/yaml-test-suite/9JBA/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9JBA/in.yaml b/Tests/Fixtures/yaml-test-suite/9JBA/in.yaml new file mode 100644 index 0000000..0242202 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9JBA/in.yaml @@ -0,0 +1,2 @@ +--- +[ a, b, c, ]#invalid diff --git a/Tests/Fixtures/yaml-test-suite/9JBA/test.event b/Tests/Fixtures/yaml-test-suite/9JBA/test.event new file mode 100644 index 0000000..fcbdae6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9JBA/test.event @@ -0,0 +1,7 @@ ++STR ++DOC --- ++SEQ [] +=VAL :a +=VAL :b +=VAL :c +-SEQ diff --git a/Tests/Fixtures/yaml-test-suite/9KAX/in.json b/Tests/Fixtures/yaml-test-suite/9KAX/in.json new file mode 100644 index 0000000..6056492 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9KAX/in.json @@ -0,0 +1,17 @@ +"scalar1" +"scalar2" +"scalar3" +{ + "key5": "value4" +} +{ + "a6": 1, + "b6": 2 +} +{ + "key8": "value7" +} +{ + "key10": "value9" +} +"value11" diff --git a/Tests/Fixtures/yaml-test-suite/9KAX/in.yaml b/Tests/Fixtures/yaml-test-suite/9KAX/in.yaml new file mode 100644 index 0000000..0ade841 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9KAX/in.yaml @@ -0,0 +1,26 @@ +--- +&a1 +!!str +scalar1 +--- +!!str +&a2 +scalar2 +--- +&a3 +!!str scalar3 +--- +&a4 !!map +&a5 !!str key5: value4 +--- +a6: 1 +&anchor6 b6: 2 +--- +!!map +&a8 !!str key8: value7 +--- +!!map +!!str &a10 key10: value9 +--- +!!str &a11 +value11 diff --git a/Tests/Fixtures/yaml-test-suite/9KAX/test.event b/Tests/Fixtures/yaml-test-suite/9KAX/test.event new file mode 100644 index 0000000..fe04562 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9KAX/test.event @@ -0,0 +1,40 @@ ++STR ++DOC --- +=VAL &a1 :scalar1 +-DOC ++DOC --- +=VAL &a2 :scalar2 +-DOC ++DOC --- +=VAL &a3 :scalar3 +-DOC ++DOC --- ++MAP &a4 +=VAL &a5 :key5 +=VAL :value4 +-MAP +-DOC ++DOC --- ++MAP +=VAL :a6 +=VAL :1 +=VAL &anchor6 :b6 +=VAL :2 +-MAP +-DOC ++DOC --- ++MAP +=VAL &a8 :key8 +=VAL :value7 +-MAP +-DOC ++DOC --- ++MAP +=VAL &a10 :key10 +=VAL :value9 +-MAP +-DOC ++DOC --- +=VAL &a11 :value11 +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9KBC/error b/Tests/Fixtures/yaml-test-suite/9KBC/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9KBC/in.yaml b/Tests/Fixtures/yaml-test-suite/9KBC/in.yaml new file mode 100644 index 0000000..f2c1654 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9KBC/in.yaml @@ -0,0 +1,2 @@ +--- key1: value1 + key2: value2 diff --git a/Tests/Fixtures/yaml-test-suite/9KBC/test.event b/Tests/Fixtures/yaml-test-suite/9KBC/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9KBC/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/9MAG/error b/Tests/Fixtures/yaml-test-suite/9MAG/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9MAG/in.yaml b/Tests/Fixtures/yaml-test-suite/9MAG/in.yaml new file mode 100644 index 0000000..868f6c6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MAG/in.yaml @@ -0,0 +1,2 @@ +--- +[ , a, b, c ] diff --git a/Tests/Fixtures/yaml-test-suite/9MAG/test.event b/Tests/Fixtures/yaml-test-suite/9MAG/test.event new file mode 100644 index 0000000..dce87f5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MAG/test.event @@ -0,0 +1,3 @@ ++STR ++DOC --- ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/9MMA/error b/Tests/Fixtures/yaml-test-suite/9MMA/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9MMA/in.yaml b/Tests/Fixtures/yaml-test-suite/9MMA/in.yaml new file mode 100644 index 0000000..6e9a0bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MMA/in.yaml @@ -0,0 +1 @@ +%YAML 1.2 diff --git a/Tests/Fixtures/yaml-test-suite/9MMA/test.event b/Tests/Fixtures/yaml-test-suite/9MMA/test.event new file mode 100644 index 0000000..e72d602 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MMA/test.event @@ -0,0 +1 @@ ++STR diff --git a/Tests/Fixtures/yaml-test-suite/9MMW/in.yaml b/Tests/Fixtures/yaml-test-suite/9MMW/in.yaml new file mode 100644 index 0000000..b9fe5e1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MMW/in.yaml @@ -0,0 +1,3 @@ +- [ YAML : separate ] +- [ "JSON like":adjacent ] +- [ {JSON: like}:adjacent ] diff --git a/Tests/Fixtures/yaml-test-suite/9MMW/test.event b/Tests/Fixtures/yaml-test-suite/9MMW/test.event new file mode 100644 index 0000000..b43022e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MMW/test.event @@ -0,0 +1,27 @@ ++STR ++DOC ++SEQ ++SEQ [] ++MAP {} +=VAL :YAML +=VAL :separate +-MAP +-SEQ ++SEQ [] ++MAP {} +=VAL "JSON like +=VAL :adjacent +-MAP +-SEQ ++SEQ [] ++MAP {} ++MAP {} +=VAL :JSON +=VAL :like +-MAP +=VAL :adjacent +-MAP +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9MQT/00/in.json b/Tests/Fixtures/yaml-test-suite/9MQT/00/in.json new file mode 100644 index 0000000..ed697c1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MQT/00/in.json @@ -0,0 +1 @@ +"a ...x b" diff --git a/Tests/Fixtures/yaml-test-suite/9MQT/00/in.yaml b/Tests/Fixtures/yaml-test-suite/9MQT/00/in.yaml new file mode 100644 index 0000000..8f86a1b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MQT/00/in.yaml @@ -0,0 +1,3 @@ +--- "a +...x +b" diff --git a/Tests/Fixtures/yaml-test-suite/9MQT/00/test.event b/Tests/Fixtures/yaml-test-suite/9MQT/00/test.event new file mode 100644 index 0000000..6b0acaf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MQT/00/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL "a ...x b +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9MQT/01/error b/Tests/Fixtures/yaml-test-suite/9MQT/01/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/9MQT/01/in.json b/Tests/Fixtures/yaml-test-suite/9MQT/01/in.json new file mode 100644 index 0000000..ed697c1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MQT/01/in.json @@ -0,0 +1 @@ +"a ...x b" diff --git a/Tests/Fixtures/yaml-test-suite/9MQT/01/in.yaml b/Tests/Fixtures/yaml-test-suite/9MQT/01/in.yaml new file mode 100644 index 0000000..ed9388b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MQT/01/in.yaml @@ -0,0 +1,3 @@ +--- "a +... x +b" diff --git a/Tests/Fixtures/yaml-test-suite/9MQT/01/test.event b/Tests/Fixtures/yaml-test-suite/9MQT/01/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9MQT/01/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/9SA2/in.json b/Tests/Fixtures/yaml-test-suite/9SA2/in.json new file mode 100644 index 0000000..d214d88 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9SA2/in.json @@ -0,0 +1,8 @@ +[ + { + "single line": "value" + }, + { + "multi line": "value" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/9SA2/in.yaml b/Tests/Fixtures/yaml-test-suite/9SA2/in.yaml new file mode 100644 index 0000000..b79124b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9SA2/in.yaml @@ -0,0 +1,4 @@ +--- +- { "single line": value} +- { "multi + line": value} diff --git a/Tests/Fixtures/yaml-test-suite/9SA2/test.event b/Tests/Fixtures/yaml-test-suite/9SA2/test.event new file mode 100644 index 0000000..ef14f8d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9SA2/test.event @@ -0,0 +1,14 @@ ++STR ++DOC --- ++SEQ ++MAP {} +=VAL "single line +=VAL :value +-MAP ++MAP {} +=VAL "multi line +=VAL :value +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9SHH/in.json b/Tests/Fixtures/yaml-test-suite/9SHH/in.json new file mode 100644 index 0000000..4e274b0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9SHH/in.json @@ -0,0 +1,4 @@ +{ + "single": "text", + "double": "text" +} diff --git a/Tests/Fixtures/yaml-test-suite/9SHH/in.yaml b/Tests/Fixtures/yaml-test-suite/9SHH/in.yaml new file mode 100644 index 0000000..04ebf69 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9SHH/in.yaml @@ -0,0 +1,2 @@ +single: 'text' +double: "text" diff --git a/Tests/Fixtures/yaml-test-suite/9SHH/test.event b/Tests/Fixtures/yaml-test-suite/9SHH/test.event new file mode 100644 index 0000000..0fce5eb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9SHH/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :single +=VAL 'text +=VAL :double +=VAL "text +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9TFX/in.json b/Tests/Fixtures/yaml-test-suite/9TFX/in.json new file mode 100644 index 0000000..2dfab84 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9TFX/in.json @@ -0,0 +1 @@ +" 1st non-empty\n2nd non-empty 3rd non-empty " diff --git a/Tests/Fixtures/yaml-test-suite/9TFX/in.yaml b/Tests/Fixtures/yaml-test-suite/9TFX/in.yaml new file mode 100644 index 0000000..5afb3f4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9TFX/in.yaml @@ -0,0 +1,5 @@ +--- +" 1st non-empty + + 2nd non-empty + 3rd non-empty " diff --git a/Tests/Fixtures/yaml-test-suite/9TFX/test.event b/Tests/Fixtures/yaml-test-suite/9TFX/test.event new file mode 100644 index 0000000..5185eb5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9TFX/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL " 1st non-empty\n2nd non-empty 3rd non-empty +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9U5K/in.json b/Tests/Fixtures/yaml-test-suite/9U5K/in.json new file mode 100644 index 0000000..f932159 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9U5K/in.json @@ -0,0 +1,14 @@ +[ + { + "item": "Super Hoop", + "quantity": 1 + }, + { + "item": "Basketball", + "quantity": 4 + }, + { + "item": "Big Shoes", + "quantity": 1 + } +] diff --git a/Tests/Fixtures/yaml-test-suite/9U5K/in.yaml b/Tests/Fixtures/yaml-test-suite/9U5K/in.yaml new file mode 100644 index 0000000..63a8ed7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9U5K/in.yaml @@ -0,0 +1,8 @@ +--- +# Products purchased +- item : Super Hoop + quantity: 1 +- item : Basketball + quantity: 4 +- item : Big Shoes + quantity: 1 diff --git a/Tests/Fixtures/yaml-test-suite/9U5K/test.event b/Tests/Fixtures/yaml-test-suite/9U5K/test.event new file mode 100644 index 0000000..d561515 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9U5K/test.event @@ -0,0 +1,24 @@ ++STR ++DOC --- ++SEQ ++MAP +=VAL :item +=VAL :Super Hoop +=VAL :quantity +=VAL :1 +-MAP ++MAP +=VAL :item +=VAL :Basketball +=VAL :quantity +=VAL :4 +-MAP ++MAP +=VAL :item +=VAL :Big Shoes +=VAL :quantity +=VAL :1 +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9WXW/in.json b/Tests/Fixtures/yaml-test-suite/9WXW/in.json new file mode 100644 index 0000000..f95cbd7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9WXW/in.json @@ -0,0 +1,2 @@ +"bar" +"bar" diff --git a/Tests/Fixtures/yaml-test-suite/9WXW/in.yaml b/Tests/Fixtures/yaml-test-suite/9WXW/in.yaml new file mode 100644 index 0000000..d79f04e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9WXW/in.yaml @@ -0,0 +1,7 @@ +# Private +!foo "bar" +... +# Global +%TAG ! tag:example.com,2000:app/ +--- +!foo "bar" diff --git a/Tests/Fixtures/yaml-test-suite/9WXW/test.event b/Tests/Fixtures/yaml-test-suite/9WXW/test.event new file mode 100644 index 0000000..0854272 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9WXW/test.event @@ -0,0 +1,8 @@ ++STR ++DOC +=VAL "bar +-DOC ... ++DOC --- +=VAL "bar +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/9YRD/in.json b/Tests/Fixtures/yaml-test-suite/9YRD/in.json new file mode 100644 index 0000000..a565abc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9YRD/in.json @@ -0,0 +1 @@ +"a b c d\ne" diff --git a/Tests/Fixtures/yaml-test-suite/9YRD/in.yaml b/Tests/Fixtures/yaml-test-suite/9YRD/in.yaml new file mode 100644 index 0000000..8a21b02 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9YRD/in.yaml @@ -0,0 +1,6 @@ +a +b + c +d + +e diff --git a/Tests/Fixtures/yaml-test-suite/9YRD/test.event b/Tests/Fixtures/yaml-test-suite/9YRD/test.event new file mode 100644 index 0000000..1d0d238 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/9YRD/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL :a b c d\ne +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/A2M4/in.json b/Tests/Fixtures/yaml-test-suite/A2M4/in.json new file mode 100644 index 0000000..848d9f6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A2M4/in.json @@ -0,0 +1,9 @@ +{ + "a": [ + "b", + [ + "c", + "d" + ] + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/A2M4/in.yaml b/Tests/Fixtures/yaml-test-suite/A2M4/in.yaml new file mode 100644 index 0000000..ac0d970 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A2M4/in.yaml @@ -0,0 +1,4 @@ +? a +: - b + - - c + - d diff --git a/Tests/Fixtures/yaml-test-suite/A2M4/test.event b/Tests/Fixtures/yaml-test-suite/A2M4/test.event new file mode 100644 index 0000000..05a3a06 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A2M4/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :a ++SEQ +=VAL :b ++SEQ +=VAL :c +=VAL :d +-SEQ +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/A6F9/in.json b/Tests/Fixtures/yaml-test-suite/A6F9/in.json new file mode 100644 index 0000000..50e1907 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A6F9/in.json @@ -0,0 +1,5 @@ +{ + "strip": "text", + "clip": "text\n", + "keep": "text\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/A6F9/in.yaml b/Tests/Fixtures/yaml-test-suite/A6F9/in.yaml new file mode 100644 index 0000000..fa6190f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A6F9/in.yaml @@ -0,0 +1,6 @@ +strip: |- + text +clip: | + text +keep: |+ + text diff --git a/Tests/Fixtures/yaml-test-suite/A6F9/test.event b/Tests/Fixtures/yaml-test-suite/A6F9/test.event new file mode 100644 index 0000000..71ef2cb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A6F9/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :strip +=VAL |text +=VAL :clip +=VAL |text\n +=VAL :keep +=VAL |text\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/A984/in.json b/Tests/Fixtures/yaml-test-suite/A984/in.json new file mode 100644 index 0000000..50ad5bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A984/in.json @@ -0,0 +1,4 @@ +{ + "a": "b c", + "d": "e f" +} diff --git a/Tests/Fixtures/yaml-test-suite/A984/in.yaml b/Tests/Fixtures/yaml-test-suite/A984/in.yaml new file mode 100644 index 0000000..62fe04a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A984/in.yaml @@ -0,0 +1,5 @@ +a: b + c +d: + e + f diff --git a/Tests/Fixtures/yaml-test-suite/A984/test.event b/Tests/Fixtures/yaml-test-suite/A984/test.event new file mode 100644 index 0000000..8edb42e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/A984/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL :b c +=VAL :d +=VAL :e f +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/AB8U/in.json b/Tests/Fixtures/yaml-test-suite/AB8U/in.json new file mode 100644 index 0000000..ea0a643 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AB8U/in.json @@ -0,0 +1,3 @@ +[ + "single multiline - sequence entry" +] diff --git a/Tests/Fixtures/yaml-test-suite/AB8U/in.yaml b/Tests/Fixtures/yaml-test-suite/AB8U/in.yaml new file mode 100644 index 0000000..abf6cec --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AB8U/in.yaml @@ -0,0 +1,2 @@ +- single multiline + - sequence entry diff --git a/Tests/Fixtures/yaml-test-suite/AB8U/test.event b/Tests/Fixtures/yaml-test-suite/AB8U/test.event new file mode 100644 index 0000000..b5fa8e9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AB8U/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ +=VAL :single multiline - sequence entry +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/AVM7/in.json b/Tests/Fixtures/yaml-test-suite/AVM7/in.json new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/AVM7/in.yaml b/Tests/Fixtures/yaml-test-suite/AVM7/in.yaml new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/AVM7/test.event b/Tests/Fixtures/yaml-test-suite/AVM7/test.event new file mode 100644 index 0000000..a8c0574 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AVM7/test.event @@ -0,0 +1,2 @@ ++STR +-STR diff --git a/Tests/Fixtures/yaml-test-suite/AZ63/in.json b/Tests/Fixtures/yaml-test-suite/AZ63/in.json new file mode 100644 index 0000000..d8d5d7e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AZ63/in.json @@ -0,0 +1,7 @@ +{ + "one": [ + 2, + 3 + ], + "four": 5 +} diff --git a/Tests/Fixtures/yaml-test-suite/AZ63/in.yaml b/Tests/Fixtures/yaml-test-suite/AZ63/in.yaml new file mode 100644 index 0000000..80eda20 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AZ63/in.yaml @@ -0,0 +1,4 @@ +one: +- 2 +- 3 +four: 5 diff --git a/Tests/Fixtures/yaml-test-suite/AZ63/test.event b/Tests/Fixtures/yaml-test-suite/AZ63/test.event new file mode 100644 index 0000000..933e2ae --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AZ63/test.event @@ -0,0 +1,13 @@ ++STR ++DOC ++MAP +=VAL :one ++SEQ +=VAL :2 +=VAL :3 +-SEQ +=VAL :four +=VAL :5 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/AZW3/in.json b/Tests/Fixtures/yaml-test-suite/AZW3/in.json new file mode 100644 index 0000000..0e62301 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AZW3/in.json @@ -0,0 +1,8 @@ +[ + { + "bla\"keks": "foo" + }, + { + "bla]keks": "foo" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/AZW3/in.yaml b/Tests/Fixtures/yaml-test-suite/AZW3/in.yaml new file mode 100644 index 0000000..c9219e9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AZW3/in.yaml @@ -0,0 +1,2 @@ +- bla"keks: foo +- bla]keks: foo diff --git a/Tests/Fixtures/yaml-test-suite/AZW3/test.event b/Tests/Fixtures/yaml-test-suite/AZW3/test.event new file mode 100644 index 0000000..d04ca7a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/AZW3/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++SEQ ++MAP +=VAL :bla"keks +=VAL :foo +-MAP ++MAP +=VAL :bla]keks +=VAL :foo +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/B3HG/in.json b/Tests/Fixtures/yaml-test-suite/B3HG/in.json new file mode 100644 index 0000000..d5cf354 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/B3HG/in.json @@ -0,0 +1 @@ +"folded text\n" diff --git a/Tests/Fixtures/yaml-test-suite/B3HG/in.yaml b/Tests/Fixtures/yaml-test-suite/B3HG/in.yaml new file mode 100644 index 0000000..668490c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/B3HG/in.yaml @@ -0,0 +1,5 @@ +--- > + folded + text + + diff --git a/Tests/Fixtures/yaml-test-suite/B3HG/test.event b/Tests/Fixtures/yaml-test-suite/B3HG/test.event new file mode 100644 index 0000000..5e7760d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/B3HG/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL >folded text\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/B63P/error b/Tests/Fixtures/yaml-test-suite/B63P/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/B63P/in.yaml b/Tests/Fixtures/yaml-test-suite/B63P/in.yaml new file mode 100644 index 0000000..142134e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/B63P/in.yaml @@ -0,0 +1,2 @@ +%YAML 1.2 +... diff --git a/Tests/Fixtures/yaml-test-suite/B63P/test.event b/Tests/Fixtures/yaml-test-suite/B63P/test.event new file mode 100644 index 0000000..e72d602 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/B63P/test.event @@ -0,0 +1 @@ ++STR diff --git a/Tests/Fixtures/yaml-test-suite/BD7L/error b/Tests/Fixtures/yaml-test-suite/BD7L/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/BD7L/in.yaml b/Tests/Fixtures/yaml-test-suite/BD7L/in.yaml new file mode 100644 index 0000000..30799d9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BD7L/in.yaml @@ -0,0 +1,3 @@ +- item1 +- item2 +invalid: x diff --git a/Tests/Fixtures/yaml-test-suite/BD7L/test.event b/Tests/Fixtures/yaml-test-suite/BD7L/test.event new file mode 100644 index 0000000..fc4db33 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BD7L/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++SEQ +=VAL :item1 +=VAL :item2 diff --git a/Tests/Fixtures/yaml-test-suite/BEC7/in.json b/Tests/Fixtures/yaml-test-suite/BEC7/in.json new file mode 100644 index 0000000..810c96e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BEC7/in.json @@ -0,0 +1 @@ +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/BEC7/in.yaml b/Tests/Fixtures/yaml-test-suite/BEC7/in.yaml new file mode 100644 index 0000000..fb55215 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BEC7/in.yaml @@ -0,0 +1,4 @@ +%YAML 1.3 # Attempt parsing + # with a warning +--- +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/BEC7/test.event b/Tests/Fixtures/yaml-test-suite/BEC7/test.event new file mode 100644 index 0000000..324d096 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BEC7/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL "foo +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/BF9H/error b/Tests/Fixtures/yaml-test-suite/BF9H/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/BF9H/in.yaml b/Tests/Fixtures/yaml-test-suite/BF9H/in.yaml new file mode 100644 index 0000000..8afd770 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BF9H/in.yaml @@ -0,0 +1,4 @@ +--- +plain: a + b # end of scalar + c diff --git a/Tests/Fixtures/yaml-test-suite/BF9H/test.event b/Tests/Fixtures/yaml-test-suite/BF9H/test.event new file mode 100644 index 0000000..1f53c3c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BF9H/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- ++MAP +=VAL :plain +=VAL :a b diff --git a/Tests/Fixtures/yaml-test-suite/BS4K/error b/Tests/Fixtures/yaml-test-suite/BS4K/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/BS4K/in.yaml b/Tests/Fixtures/yaml-test-suite/BS4K/in.yaml new file mode 100644 index 0000000..5ddae76 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BS4K/in.yaml @@ -0,0 +1,2 @@ +word1 # comment +word2 diff --git a/Tests/Fixtures/yaml-test-suite/BS4K/test.event b/Tests/Fixtures/yaml-test-suite/BS4K/test.event new file mode 100644 index 0000000..d7f91c1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BS4K/test.event @@ -0,0 +1,4 @@ ++STR ++DOC +=VAL :word1 +-DOC diff --git a/Tests/Fixtures/yaml-test-suite/BU8L/in.json b/Tests/Fixtures/yaml-test-suite/BU8L/in.json new file mode 100644 index 0000000..1609d45 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BU8L/in.json @@ -0,0 +1,5 @@ +{ + "key": { + "a": "b" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/BU8L/in.yaml b/Tests/Fixtures/yaml-test-suite/BU8L/in.yaml new file mode 100644 index 0000000..35d556d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BU8L/in.yaml @@ -0,0 +1,3 @@ +key: &anchor + !!map + a: b diff --git a/Tests/Fixtures/yaml-test-suite/BU8L/test.event b/Tests/Fixtures/yaml-test-suite/BU8L/test.event new file mode 100644 index 0000000..babc4f4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/BU8L/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++MAP +=VAL :key ++MAP &anchor +=VAL :a +=VAL :b +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/C2DT/in.json b/Tests/Fixtures/yaml-test-suite/C2DT/in.json new file mode 100644 index 0000000..e522f08 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C2DT/in.json @@ -0,0 +1,5 @@ +{ + "adjacent": "value", + "readable": "value", + "empty": null +} diff --git a/Tests/Fixtures/yaml-test-suite/C2DT/in.yaml b/Tests/Fixtures/yaml-test-suite/C2DT/in.yaml new file mode 100644 index 0000000..7fc069c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C2DT/in.yaml @@ -0,0 +1,5 @@ +{ +"adjacent":value, +"readable": value, +"empty": +} diff --git a/Tests/Fixtures/yaml-test-suite/C2DT/test.event b/Tests/Fixtures/yaml-test-suite/C2DT/test.event new file mode 100644 index 0000000..446750a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C2DT/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP {} +=VAL "adjacent +=VAL :value +=VAL "readable +=VAL :value +=VAL "empty +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/C2SP/error b/Tests/Fixtures/yaml-test-suite/C2SP/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/C2SP/in.yaml b/Tests/Fixtures/yaml-test-suite/C2SP/in.yaml new file mode 100644 index 0000000..bb88dde --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C2SP/in.yaml @@ -0,0 +1,2 @@ +[23 +]: 42 diff --git a/Tests/Fixtures/yaml-test-suite/C2SP/test.event b/Tests/Fixtures/yaml-test-suite/C2SP/test.event new file mode 100644 index 0000000..af9cc7d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C2SP/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ [] +=VAL :23 diff --git a/Tests/Fixtures/yaml-test-suite/C4HZ/in.json b/Tests/Fixtures/yaml-test-suite/C4HZ/in.json new file mode 100644 index 0000000..de484e0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C4HZ/in.json @@ -0,0 +1,27 @@ +[ + { + "center": { + "x": 73, + "y": 129 + }, + "radius": 7 + }, + { + "start": { + "x": 73, + "y": 129 + }, + "finish": { + "x": 89, + "y": 102 + } + }, + { + "start": { + "x": 73, + "y": 129 + }, + "color": 16772795, + "text": "Pretty vector drawing." + } +] diff --git a/Tests/Fixtures/yaml-test-suite/C4HZ/in.yaml b/Tests/Fixtures/yaml-test-suite/C4HZ/in.yaml new file mode 100644 index 0000000..1180757 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C4HZ/in.yaml @@ -0,0 +1,14 @@ +%TAG ! tag:clarkevans.com,2002: +--- !shape + # Use the ! handle for presenting + # tag:clarkevans.com,2002:circle +- !circle + center: &ORIGIN {x: 73, y: 129} + radius: 7 +- !line + start: *ORIGIN + finish: { x: 89, y: 102 } +- !label + start: *ORIGIN + color: 0xFFEEBB + text: Pretty vector drawing. diff --git a/Tests/Fixtures/yaml-test-suite/C4HZ/test.event b/Tests/Fixtures/yaml-test-suite/C4HZ/test.event new file mode 100644 index 0000000..dc77e1a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/C4HZ/test.event @@ -0,0 +1,36 @@ ++STR ++DOC --- ++SEQ ++MAP +=VAL :center ++MAP {} &ORIGIN +=VAL :x +=VAL :73 +=VAL :y +=VAL :129 +-MAP +=VAL :radius +=VAL :7 +-MAP ++MAP +=VAL :start +=ALI *ORIGIN +=VAL :finish ++MAP {} +=VAL :x +=VAL :89 +=VAL :y +=VAL :102 +-MAP +-MAP ++MAP +=VAL :start +=ALI *ORIGIN +=VAL :color +=VAL :0xFFEEBB +=VAL :text +=VAL :Pretty vector drawing. +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/CC74/in.json b/Tests/Fixtures/yaml-test-suite/CC74/in.json new file mode 100644 index 0000000..196e587 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CC74/in.json @@ -0,0 +1 @@ +"bar" diff --git a/Tests/Fixtures/yaml-test-suite/CC74/in.yaml b/Tests/Fixtures/yaml-test-suite/CC74/in.yaml new file mode 100644 index 0000000..690f138 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CC74/in.yaml @@ -0,0 +1,3 @@ +%TAG !e! tag:example.com,2000:app/ +--- +!e!foo "bar" diff --git a/Tests/Fixtures/yaml-test-suite/CC74/test.event b/Tests/Fixtures/yaml-test-suite/CC74/test.event new file mode 100644 index 0000000..7c0ff3a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CC74/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL "bar +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/CFD4/in.yaml b/Tests/Fixtures/yaml-test-suite/CFD4/in.yaml new file mode 100644 index 0000000..503d73a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CFD4/in.yaml @@ -0,0 +1,2 @@ +- [ : empty key ] +- [: another empty key] diff --git a/Tests/Fixtures/yaml-test-suite/CFD4/test.event b/Tests/Fixtures/yaml-test-suite/CFD4/test.event new file mode 100644 index 0000000..9258b61 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CFD4/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++SEQ ++SEQ [] ++MAP {} +=VAL : +=VAL :empty key +-MAP +-SEQ ++SEQ [] ++MAP {} +=VAL : +=VAL :another empty key +-MAP +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/CML9/error b/Tests/Fixtures/yaml-test-suite/CML9/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/CML9/in.yaml b/Tests/Fixtures/yaml-test-suite/CML9/in.yaml new file mode 100644 index 0000000..b2c39a5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CML9/in.yaml @@ -0,0 +1,3 @@ +key: [ word1 +# xxx + word2 ] diff --git a/Tests/Fixtures/yaml-test-suite/CML9/test.event b/Tests/Fixtures/yaml-test-suite/CML9/test.event new file mode 100644 index 0000000..5f669e2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CML9/test.event @@ -0,0 +1,6 @@ ++STR ++DOC ++MAP +=VAL :key ++SEQ [] +=VAL :word1 diff --git a/Tests/Fixtures/yaml-test-suite/CN3R/in.json b/Tests/Fixtures/yaml-test-suite/CN3R/in.json new file mode 100644 index 0000000..28eb29e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CN3R/in.json @@ -0,0 +1,14 @@ +[ + { + "a": "b" + }, + { + "c": "d" + }, + { + "e": "f" + }, + { + "g": "h" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/CN3R/in.yaml b/Tests/Fixtures/yaml-test-suite/CN3R/in.yaml new file mode 100644 index 0000000..8345dfc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CN3R/in.yaml @@ -0,0 +1,6 @@ +&flowseq [ + a: b, + &c c: d, + { &e e: f }, + &g { g: h } +] diff --git a/Tests/Fixtures/yaml-test-suite/CN3R/test.event b/Tests/Fixtures/yaml-test-suite/CN3R/test.event new file mode 100644 index 0000000..db80b1a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CN3R/test.event @@ -0,0 +1,22 @@ ++STR ++DOC ++SEQ [] &flowseq ++MAP {} +=VAL :a +=VAL :b +-MAP ++MAP {} +=VAL &c :c +=VAL :d +-MAP ++MAP {} +=VAL &e :e +=VAL :f +-MAP ++MAP {} &g +=VAL :g +=VAL :h +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/CPZ3/in.json b/Tests/Fixtures/yaml-test-suite/CPZ3/in.json new file mode 100644 index 0000000..977fceb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CPZ3/in.json @@ -0,0 +1,3 @@ +{ + "tab": "\tstring" +} diff --git a/Tests/Fixtures/yaml-test-suite/CPZ3/in.yaml b/Tests/Fixtures/yaml-test-suite/CPZ3/in.yaml new file mode 100644 index 0000000..082400b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CPZ3/in.yaml @@ -0,0 +1,2 @@ +--- +tab: "\tstring" diff --git a/Tests/Fixtures/yaml-test-suite/CPZ3/test.event b/Tests/Fixtures/yaml-test-suite/CPZ3/test.event new file mode 100644 index 0000000..e83079e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CPZ3/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :tab +=VAL "\tstring +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/CQ3W/error b/Tests/Fixtures/yaml-test-suite/CQ3W/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/CQ3W/in.yaml b/Tests/Fixtures/yaml-test-suite/CQ3W/in.yaml new file mode 100644 index 0000000..c8d7e45 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CQ3W/in.yaml @@ -0,0 +1,2 @@ +--- +key: "missing closing quote diff --git a/Tests/Fixtures/yaml-test-suite/CQ3W/test.event b/Tests/Fixtures/yaml-test-suite/CQ3W/test.event new file mode 100644 index 0000000..a15029a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CQ3W/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :key diff --git a/Tests/Fixtures/yaml-test-suite/CT4Q/in.json b/Tests/Fixtures/yaml-test-suite/CT4Q/in.json new file mode 100644 index 0000000..6342cb2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CT4Q/in.json @@ -0,0 +1,5 @@ +[ + { + "foo bar": "baz" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/CT4Q/in.yaml b/Tests/Fixtures/yaml-test-suite/CT4Q/in.yaml new file mode 100644 index 0000000..19dc4f5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CT4Q/in.yaml @@ -0,0 +1,4 @@ +[ +? foo + bar : baz +] diff --git a/Tests/Fixtures/yaml-test-suite/CT4Q/test.event b/Tests/Fixtures/yaml-test-suite/CT4Q/test.event new file mode 100644 index 0000000..94fcfe0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CT4Q/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ [] ++MAP {} +=VAL :foo bar +=VAL :baz +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/CTN5/error b/Tests/Fixtures/yaml-test-suite/CTN5/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/CTN5/in.yaml b/Tests/Fixtures/yaml-test-suite/CTN5/in.yaml new file mode 100644 index 0000000..001f836 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CTN5/in.yaml @@ -0,0 +1,2 @@ +--- +[ a, b, c, , ] diff --git a/Tests/Fixtures/yaml-test-suite/CTN5/test.event b/Tests/Fixtures/yaml-test-suite/CTN5/test.event new file mode 100644 index 0000000..0f4c5e1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CTN5/test.event @@ -0,0 +1,6 @@ ++STR ++DOC --- ++SEQ [] +=VAL :a +=VAL :b +=VAL :c diff --git a/Tests/Fixtures/yaml-test-suite/CUP7/in.json b/Tests/Fixtures/yaml-test-suite/CUP7/in.json new file mode 100644 index 0000000..55f1478 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CUP7/in.json @@ -0,0 +1,4 @@ +{ + "anchored": "value", + "alias": "value" +} diff --git a/Tests/Fixtures/yaml-test-suite/CUP7/in.yaml b/Tests/Fixtures/yaml-test-suite/CUP7/in.yaml new file mode 100644 index 0000000..7a1f9b3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CUP7/in.yaml @@ -0,0 +1,2 @@ +anchored: !local &anchor value +alias: *anchor diff --git a/Tests/Fixtures/yaml-test-suite/CUP7/test.event b/Tests/Fixtures/yaml-test-suite/CUP7/test.event new file mode 100644 index 0000000..9575f21 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CUP7/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :anchored +=VAL &anchor :value +=VAL :alias +=ALI *anchor +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/CVW2/error b/Tests/Fixtures/yaml-test-suite/CVW2/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/CVW2/in.yaml b/Tests/Fixtures/yaml-test-suite/CVW2/in.yaml new file mode 100644 index 0000000..0f185f0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CVW2/in.yaml @@ -0,0 +1,3 @@ +--- +[ a, b, c,#invalid +] diff --git a/Tests/Fixtures/yaml-test-suite/CVW2/test.event b/Tests/Fixtures/yaml-test-suite/CVW2/test.event new file mode 100644 index 0000000..0f4c5e1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CVW2/test.event @@ -0,0 +1,6 @@ ++STR ++DOC --- ++SEQ [] +=VAL :a +=VAL :b +=VAL :c diff --git a/Tests/Fixtures/yaml-test-suite/CXX2/error b/Tests/Fixtures/yaml-test-suite/CXX2/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/CXX2/in.yaml b/Tests/Fixtures/yaml-test-suite/CXX2/in.yaml new file mode 100644 index 0000000..9c00120 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CXX2/in.yaml @@ -0,0 +1 @@ +--- &anchor a: b diff --git a/Tests/Fixtures/yaml-test-suite/CXX2/test.event b/Tests/Fixtures/yaml-test-suite/CXX2/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/CXX2/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/D49Q/error b/Tests/Fixtures/yaml-test-suite/D49Q/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/D49Q/in.yaml b/Tests/Fixtures/yaml-test-suite/D49Q/in.yaml new file mode 100644 index 0000000..edd180a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D49Q/in.yaml @@ -0,0 +1,3 @@ +'a\nb': 1 +'c + d': 1 diff --git a/Tests/Fixtures/yaml-test-suite/D49Q/test.event b/Tests/Fixtures/yaml-test-suite/D49Q/test.event new file mode 100644 index 0000000..c38deb4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D49Q/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL 'a\\nb +=VAL :1 diff --git a/Tests/Fixtures/yaml-test-suite/D83L/in.json b/Tests/Fixtures/yaml-test-suite/D83L/in.json new file mode 100644 index 0000000..179dcbd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D83L/in.json @@ -0,0 +1,4 @@ +[ + "explicit indent and chomp", + "chomp and explicit indent" +] diff --git a/Tests/Fixtures/yaml-test-suite/D83L/in.yaml b/Tests/Fixtures/yaml-test-suite/D83L/in.yaml new file mode 100644 index 0000000..3d603d1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D83L/in.yaml @@ -0,0 +1,4 @@ +- |2- + explicit indent and chomp +- |-2 + chomp and explicit indent diff --git a/Tests/Fixtures/yaml-test-suite/D83L/test.event b/Tests/Fixtures/yaml-test-suite/D83L/test.event new file mode 100644 index 0000000..a32aecd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D83L/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++SEQ +=VAL |explicit indent and chomp +=VAL |chomp and explicit indent +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/D88J/in.json b/Tests/Fixtures/yaml-test-suite/D88J/in.json new file mode 100644 index 0000000..93f2131 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D88J/in.json @@ -0,0 +1,6 @@ +{ + "a": [ + "b", + "c" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/D88J/in.yaml b/Tests/Fixtures/yaml-test-suite/D88J/in.yaml new file mode 100644 index 0000000..8238fdf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D88J/in.yaml @@ -0,0 +1 @@ +a: [b, c] diff --git a/Tests/Fixtures/yaml-test-suite/D88J/test.event b/Tests/Fixtures/yaml-test-suite/D88J/test.event new file mode 100644 index 0000000..367b87c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D88J/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++MAP +=VAL :a ++SEQ [] +=VAL :b +=VAL :c +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/D9TU/in.json b/Tests/Fixtures/yaml-test-suite/D9TU/in.json new file mode 100644 index 0000000..c8c4105 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D9TU/in.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/D9TU/in.yaml b/Tests/Fixtures/yaml-test-suite/D9TU/in.yaml new file mode 100644 index 0000000..20e9ff3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D9TU/in.yaml @@ -0,0 +1 @@ +foo: bar diff --git a/Tests/Fixtures/yaml-test-suite/D9TU/test.event b/Tests/Fixtures/yaml-test-suite/D9TU/test.event new file mode 100644 index 0000000..bb745c2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/D9TU/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DBG4/in.json b/Tests/Fixtures/yaml-test-suite/DBG4/in.json new file mode 100644 index 0000000..a90aeee --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DBG4/in.json @@ -0,0 +1,14 @@ +[ + "::vector", + ": - ()", + "Up, up, and away!", + -123, + "http://example.com/foo#bar", + [ + "::vector", + ": - ()", + "Up, up and away!", + -123, + "http://example.com/foo#bar" + ] +] diff --git a/Tests/Fixtures/yaml-test-suite/DBG4/in.yaml b/Tests/Fixtures/yaml-test-suite/DBG4/in.yaml new file mode 100644 index 0000000..7ed369f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DBG4/in.yaml @@ -0,0 +1,12 @@ +# Outside flow collection: +- ::vector +- ": - ()" +- Up, up, and away! +- -123 +- http://example.com/foo#bar +# Inside flow collection: +- [ ::vector, + ": - ()", + "Up, up and away!", + -123, + http://example.com/foo#bar ] diff --git a/Tests/Fixtures/yaml-test-suite/DBG4/test.event b/Tests/Fixtures/yaml-test-suite/DBG4/test.event new file mode 100644 index 0000000..d4d36d5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DBG4/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++SEQ +=VAL :::vector +=VAL ": - () +=VAL :Up, up, and away! +=VAL :-123 +=VAL :http://example.com/foo#bar ++SEQ [] +=VAL :::vector +=VAL ": - () +=VAL "Up, up and away! +=VAL :-123 +=VAL :http://example.com/foo#bar +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DC7X/in.json b/Tests/Fixtures/yaml-test-suite/DC7X/in.json new file mode 100644 index 0000000..f76eb33 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DC7X/in.json @@ -0,0 +1,7 @@ +{ + "a": "b", + "seq": [ + "a" + ], + "c": "d" +} diff --git a/Tests/Fixtures/yaml-test-suite/DC7X/in.yaml b/Tests/Fixtures/yaml-test-suite/DC7X/in.yaml new file mode 100644 index 0000000..42ad1a9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DC7X/in.yaml @@ -0,0 +1,4 @@ +a: b +seq: + - a +c: d #X diff --git a/Tests/Fixtures/yaml-test-suite/DC7X/test.event b/Tests/Fixtures/yaml-test-suite/DC7X/test.event new file mode 100644 index 0000000..8c8a18b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DC7X/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL :b +=VAL :seq ++SEQ +=VAL :a +-SEQ +=VAL :c +=VAL :d +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DE56/00/in.json b/Tests/Fixtures/yaml-test-suite/DE56/00/in.json new file mode 100644 index 0000000..03179cd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/00/in.json @@ -0,0 +1 @@ +"1 trailing\t tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/00/in.yaml b/Tests/Fixtures/yaml-test-suite/DE56/00/in.yaml new file mode 100644 index 0000000..a235094 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/00/in.yaml @@ -0,0 +1,2 @@ +"1 trailing\t + tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/00/test.event b/Tests/Fixtures/yaml-test-suite/DE56/00/test.event new file mode 100644 index 0000000..9737ff8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/00/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "1 trailing\t tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DE56/01/in.json b/Tests/Fixtures/yaml-test-suite/DE56/01/in.json new file mode 100644 index 0000000..ade6481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/01/in.json @@ -0,0 +1 @@ +"2 trailing\t tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/01/in.yaml b/Tests/Fixtures/yaml-test-suite/DE56/01/in.yaml new file mode 100644 index 0000000..006f12a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/01/in.yaml @@ -0,0 +1,2 @@ +"2 trailing\t + tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/01/test.event b/Tests/Fixtures/yaml-test-suite/DE56/01/test.event new file mode 100644 index 0000000..c288aea --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/01/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "2 trailing\t tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DE56/02/in.json b/Tests/Fixtures/yaml-test-suite/DE56/02/in.json new file mode 100644 index 0000000..611058e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/02/in.json @@ -0,0 +1 @@ +"3 trailing\t tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/02/in.yaml b/Tests/Fixtures/yaml-test-suite/DE56/02/in.yaml new file mode 100644 index 0000000..b06a045 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/02/in.yaml @@ -0,0 +1,2 @@ +"3 trailing\ + tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/02/test.event b/Tests/Fixtures/yaml-test-suite/DE56/02/test.event new file mode 100644 index 0000000..3d461f5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/02/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "3 trailing\t tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DE56/03/in.json b/Tests/Fixtures/yaml-test-suite/DE56/03/in.json new file mode 100644 index 0000000..388f4e4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/03/in.json @@ -0,0 +1 @@ +"4 trailing\t tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/03/in.yaml b/Tests/Fixtures/yaml-test-suite/DE56/03/in.yaml new file mode 100644 index 0000000..13694b0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/03/in.yaml @@ -0,0 +1,2 @@ +"4 trailing\ + tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/03/test.event b/Tests/Fixtures/yaml-test-suite/DE56/03/test.event new file mode 100644 index 0000000..3ad2c5e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/03/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "4 trailing\t tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DE56/04/in.json b/Tests/Fixtures/yaml-test-suite/DE56/04/in.json new file mode 100644 index 0000000..c83327d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/04/in.json @@ -0,0 +1 @@ +"5 trailing tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/04/in.yaml b/Tests/Fixtures/yaml-test-suite/DE56/04/in.yaml new file mode 100644 index 0000000..5f8ff1c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/04/in.yaml @@ -0,0 +1,2 @@ +"5 trailing + tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/04/test.event b/Tests/Fixtures/yaml-test-suite/DE56/04/test.event new file mode 100644 index 0000000..59b53ff --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/04/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "5 trailing tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DE56/05/in.json b/Tests/Fixtures/yaml-test-suite/DE56/05/in.json new file mode 100644 index 0000000..56138d1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/05/in.json @@ -0,0 +1 @@ +"6 trailing tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/05/in.yaml b/Tests/Fixtures/yaml-test-suite/DE56/05/in.yaml new file mode 100644 index 0000000..f25a33a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/05/in.yaml @@ -0,0 +1,2 @@ +"6 trailing + tab" diff --git a/Tests/Fixtures/yaml-test-suite/DE56/05/test.event b/Tests/Fixtures/yaml-test-suite/DE56/05/test.event new file mode 100644 index 0000000..80b5588 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DE56/05/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "6 trailing tab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DFF7/in.yaml b/Tests/Fixtures/yaml-test-suite/DFF7/in.yaml new file mode 100644 index 0000000..cb84a99 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DFF7/in.yaml @@ -0,0 +1,5 @@ +{ +? explicit: entry, +implicit: entry, +? +} diff --git a/Tests/Fixtures/yaml-test-suite/DFF7/test.event b/Tests/Fixtures/yaml-test-suite/DFF7/test.event new file mode 100644 index 0000000..56987cb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DFF7/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP {} +=VAL :explicit +=VAL :entry +=VAL :implicit +=VAL :entry +=VAL : +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DHP8/in.json b/Tests/Fixtures/yaml-test-suite/DHP8/in.json new file mode 100644 index 0000000..1866413 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DHP8/in.json @@ -0,0 +1,5 @@ +[ + "foo", + "bar", + 42 +] diff --git a/Tests/Fixtures/yaml-test-suite/DHP8/in.yaml b/Tests/Fixtures/yaml-test-suite/DHP8/in.yaml new file mode 100644 index 0000000..bf34158 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DHP8/in.yaml @@ -0,0 +1 @@ +[foo, bar, 42] diff --git a/Tests/Fixtures/yaml-test-suite/DHP8/test.event b/Tests/Fixtures/yaml-test-suite/DHP8/test.event new file mode 100644 index 0000000..29ed61c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DHP8/test.event @@ -0,0 +1,9 @@ ++STR ++DOC ++SEQ [] +=VAL :foo +=VAL :bar +=VAL :42 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK3J/in.json b/Tests/Fixtures/yaml-test-suite/DK3J/in.json new file mode 100644 index 0000000..ce8e836 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK3J/in.json @@ -0,0 +1 @@ +"line1 # no comment line3\n" diff --git a/Tests/Fixtures/yaml-test-suite/DK3J/in.yaml b/Tests/Fixtures/yaml-test-suite/DK3J/in.yaml new file mode 100644 index 0000000..ffb9aeb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK3J/in.yaml @@ -0,0 +1,4 @@ +--- > +line1 +# no comment +line3 diff --git a/Tests/Fixtures/yaml-test-suite/DK3J/test.event b/Tests/Fixtures/yaml-test-suite/DK3J/test.event new file mode 100644 index 0000000..425f108 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK3J/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL >line1 # no comment line3\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK4H/error b/Tests/Fixtures/yaml-test-suite/DK4H/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/DK4H/in.yaml b/Tests/Fixtures/yaml-test-suite/DK4H/in.yaml new file mode 100644 index 0000000..c7a31c9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK4H/in.yaml @@ -0,0 +1,3 @@ +--- +[ key + : value ] diff --git a/Tests/Fixtures/yaml-test-suite/DK4H/test.event b/Tests/Fixtures/yaml-test-suite/DK4H/test.event new file mode 100644 index 0000000..a0d1e7b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK4H/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++SEQ [] +=VAL :key diff --git a/Tests/Fixtures/yaml-test-suite/DK95/00/in.json b/Tests/Fixtures/yaml-test-suite/DK95/00/in.json new file mode 100644 index 0000000..d7b2eeb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/00/in.json @@ -0,0 +1,3 @@ +{ + "foo" : "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/00/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/00/in.yaml new file mode 100644 index 0000000..420d531 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/00/in.yaml @@ -0,0 +1,2 @@ +foo: + bar diff --git a/Tests/Fixtures/yaml-test-suite/DK95/00/test.event b/Tests/Fixtures/yaml-test-suite/DK95/00/test.event new file mode 100644 index 0000000..bb745c2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/00/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK95/01/error b/Tests/Fixtures/yaml-test-suite/DK95/01/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/DK95/01/in.json b/Tests/Fixtures/yaml-test-suite/DK95/01/in.json new file mode 100644 index 0000000..d7b2eeb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/01/in.json @@ -0,0 +1,3 @@ +{ + "foo" : "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/01/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/01/in.yaml new file mode 100644 index 0000000..97fa247 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/01/in.yaml @@ -0,0 +1,2 @@ +foo: "bar + baz" diff --git a/Tests/Fixtures/yaml-test-suite/DK95/01/test.event b/Tests/Fixtures/yaml-test-suite/DK95/01/test.event new file mode 100644 index 0000000..a29c31a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/01/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :foo diff --git a/Tests/Fixtures/yaml-test-suite/DK95/02/in.json b/Tests/Fixtures/yaml-test-suite/DK95/02/in.json new file mode 100644 index 0000000..f86c8d6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/02/in.json @@ -0,0 +1,3 @@ +{ + "foo" : "bar baz" +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/02/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/02/in.yaml new file mode 100644 index 0000000..422933c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/02/in.yaml @@ -0,0 +1,2 @@ +foo: "bar + baz" diff --git a/Tests/Fixtures/yaml-test-suite/DK95/02/test.event b/Tests/Fixtures/yaml-test-suite/DK95/02/test.event new file mode 100644 index 0000000..3e3fb78 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/02/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL "bar baz +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK95/03/in.json b/Tests/Fixtures/yaml-test-suite/DK95/03/in.json new file mode 100644 index 0000000..31ce888 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/03/in.json @@ -0,0 +1,3 @@ +{ + "foo" : 1 +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/03/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/03/in.yaml new file mode 100644 index 0000000..87cf24e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/03/in.yaml @@ -0,0 +1,2 @@ + +foo: 1 diff --git a/Tests/Fixtures/yaml-test-suite/DK95/03/test.event b/Tests/Fixtures/yaml-test-suite/DK95/03/test.event new file mode 100644 index 0000000..2ac9cec --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/03/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :1 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK95/04/in.json b/Tests/Fixtures/yaml-test-suite/DK95/04/in.json new file mode 100644 index 0000000..eed797b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/04/in.json @@ -0,0 +1,4 @@ +{ + "foo" : 1, + "bar" : 2 +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/04/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/04/in.yaml new file mode 100644 index 0000000..077ba0b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/04/in.yaml @@ -0,0 +1,3 @@ +foo: 1 + +bar: 2 diff --git a/Tests/Fixtures/yaml-test-suite/DK95/04/test.event b/Tests/Fixtures/yaml-test-suite/DK95/04/test.event new file mode 100644 index 0000000..005f07f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/04/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :1 +=VAL :bar +=VAL :2 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK95/05/in.json b/Tests/Fixtures/yaml-test-suite/DK95/05/in.json new file mode 100644 index 0000000..eed797b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/05/in.json @@ -0,0 +1,4 @@ +{ + "foo" : 1, + "bar" : 2 +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/05/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/05/in.yaml new file mode 100644 index 0000000..fea60bc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/05/in.yaml @@ -0,0 +1,3 @@ +foo: 1 + +bar: 2 diff --git a/Tests/Fixtures/yaml-test-suite/DK95/05/test.event b/Tests/Fixtures/yaml-test-suite/DK95/05/test.event new file mode 100644 index 0000000..005f07f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/05/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :1 +=VAL :bar +=VAL :2 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK95/06/error b/Tests/Fixtures/yaml-test-suite/DK95/06/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/DK95/06/in.json b/Tests/Fixtures/yaml-test-suite/DK95/06/in.json new file mode 100644 index 0000000..eed797b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/06/in.json @@ -0,0 +1,4 @@ +{ + "foo" : 1, + "bar" : 2 +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/06/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/06/in.yaml new file mode 100644 index 0000000..6bda856 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/06/in.yaml @@ -0,0 +1,3 @@ +foo: + a: 1 + b: 2 diff --git a/Tests/Fixtures/yaml-test-suite/DK95/06/test.event b/Tests/Fixtures/yaml-test-suite/DK95/06/test.event new file mode 100644 index 0000000..5733f5d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/06/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++MAP +=VAL :foo ++MAP +=VAL :a +=VAL :1 diff --git a/Tests/Fixtures/yaml-test-suite/DK95/07/in.json b/Tests/Fixtures/yaml-test-suite/DK95/07/in.json new file mode 100644 index 0000000..19765bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/07/in.json @@ -0,0 +1 @@ +null diff --git a/Tests/Fixtures/yaml-test-suite/DK95/07/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/07/in.yaml new file mode 100644 index 0000000..9ad1ed2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/07/in.yaml @@ -0,0 +1,3 @@ +%YAML 1.2 + +--- diff --git a/Tests/Fixtures/yaml-test-suite/DK95/07/test.event b/Tests/Fixtures/yaml-test-suite/DK95/07/test.event new file mode 100644 index 0000000..e7a400d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/07/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DK95/08/in.json b/Tests/Fixtures/yaml-test-suite/DK95/08/in.json new file mode 100644 index 0000000..0dc83aa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/08/in.json @@ -0,0 +1,3 @@ +{ + "foo" : "bar baz \t \t " +} diff --git a/Tests/Fixtures/yaml-test-suite/DK95/08/in.yaml b/Tests/Fixtures/yaml-test-suite/DK95/08/in.yaml new file mode 100644 index 0000000..1ae7eca --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/08/in.yaml @@ -0,0 +1,2 @@ +foo: "bar + baz " diff --git a/Tests/Fixtures/yaml-test-suite/DK95/08/test.event b/Tests/Fixtures/yaml-test-suite/DK95/08/test.event new file mode 100644 index 0000000..1f6f8ed --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DK95/08/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL "bar baz \t \t +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/DMG6/error b/Tests/Fixtures/yaml-test-suite/DMG6/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/DMG6/in.yaml b/Tests/Fixtures/yaml-test-suite/DMG6/in.yaml new file mode 100644 index 0000000..148a693 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DMG6/in.yaml @@ -0,0 +1,3 @@ +key: + ok: 1 + wrong: 2 diff --git a/Tests/Fixtures/yaml-test-suite/DMG6/test.event b/Tests/Fixtures/yaml-test-suite/DMG6/test.event new file mode 100644 index 0000000..bdca6a4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DMG6/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :key ++MAP +=VAL :ok +=VAL :1 +-MAP diff --git a/Tests/Fixtures/yaml-test-suite/DWX9/in.json b/Tests/Fixtures/yaml-test-suite/DWX9/in.json new file mode 100644 index 0000000..6383f8d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DWX9/in.json @@ -0,0 +1 @@ +"\n\nliteral\n \n\ntext\n" diff --git a/Tests/Fixtures/yaml-test-suite/DWX9/in.yaml b/Tests/Fixtures/yaml-test-suite/DWX9/in.yaml new file mode 100644 index 0000000..9d537cb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DWX9/in.yaml @@ -0,0 +1,9 @@ +| + + + literal + + + text + + # Comment diff --git a/Tests/Fixtures/yaml-test-suite/DWX9/test.event b/Tests/Fixtures/yaml-test-suite/DWX9/test.event new file mode 100644 index 0000000..0281dfe --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/DWX9/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL |\n\nliteral\n \n\ntext\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/E76Z/in.json b/Tests/Fixtures/yaml-test-suite/E76Z/in.json new file mode 100644 index 0000000..a9b2dde --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/E76Z/in.json @@ -0,0 +1,4 @@ +{ + "a": "b", + "b": "a" +} diff --git a/Tests/Fixtures/yaml-test-suite/E76Z/in.yaml b/Tests/Fixtures/yaml-test-suite/E76Z/in.yaml new file mode 100644 index 0000000..756ff71 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/E76Z/in.yaml @@ -0,0 +1,2 @@ +&a a: &b b +*b : *a diff --git a/Tests/Fixtures/yaml-test-suite/E76Z/test.event b/Tests/Fixtures/yaml-test-suite/E76Z/test.event new file mode 100644 index 0000000..6cf1b41 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/E76Z/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL &a :a +=VAL &b :b +=ALI *b +=ALI *a +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/EB22/error b/Tests/Fixtures/yaml-test-suite/EB22/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/EB22/in.yaml b/Tests/Fixtures/yaml-test-suite/EB22/in.yaml new file mode 100644 index 0000000..2c7dd1d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EB22/in.yaml @@ -0,0 +1,5 @@ +--- +scalar1 # comment +%YAML 1.2 +--- +scalar2 diff --git a/Tests/Fixtures/yaml-test-suite/EB22/test.event b/Tests/Fixtures/yaml-test-suite/EB22/test.event new file mode 100644 index 0000000..a1ffd68 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EB22/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- +=VAL :scalar1 +-DOC diff --git a/Tests/Fixtures/yaml-test-suite/EHF6/in.json b/Tests/Fixtures/yaml-test-suite/EHF6/in.json new file mode 100644 index 0000000..d5d1744 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EHF6/in.json @@ -0,0 +1,6 @@ +{ + "k": [ + "a", + "b" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/EHF6/in.yaml b/Tests/Fixtures/yaml-test-suite/EHF6/in.yaml new file mode 100644 index 0000000..f69ccde --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EHF6/in.yaml @@ -0,0 +1,4 @@ +!!map { + k: !!seq + [ a, !!str b] +} diff --git a/Tests/Fixtures/yaml-test-suite/EHF6/test.event b/Tests/Fixtures/yaml-test-suite/EHF6/test.event new file mode 100644 index 0000000..84530d2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EHF6/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++MAP {} +=VAL :k ++SEQ [] +=VAL :a +=VAL :b +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/EW3V/error b/Tests/Fixtures/yaml-test-suite/EW3V/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/EW3V/in.yaml b/Tests/Fixtures/yaml-test-suite/EW3V/in.yaml new file mode 100644 index 0000000..433a5f1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EW3V/in.yaml @@ -0,0 +1,2 @@ +k1: v1 + k2: v2 diff --git a/Tests/Fixtures/yaml-test-suite/EW3V/test.event b/Tests/Fixtures/yaml-test-suite/EW3V/test.event new file mode 100644 index 0000000..0fa4b30 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EW3V/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :k1 diff --git a/Tests/Fixtures/yaml-test-suite/EX5H/in.json b/Tests/Fixtures/yaml-test-suite/EX5H/in.json new file mode 100644 index 0000000..a565abc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EX5H/in.json @@ -0,0 +1 @@ +"a b c d\ne" diff --git a/Tests/Fixtures/yaml-test-suite/EX5H/in.yaml b/Tests/Fixtures/yaml-test-suite/EX5H/in.yaml new file mode 100644 index 0000000..0e75a65 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EX5H/in.yaml @@ -0,0 +1,7 @@ +--- +a +b + c +d + +e diff --git a/Tests/Fixtures/yaml-test-suite/EX5H/test.event b/Tests/Fixtures/yaml-test-suite/EX5H/test.event new file mode 100644 index 0000000..c92cc06 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EX5H/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :a b c d\ne +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/EXG3/in.json b/Tests/Fixtures/yaml-test-suite/EXG3/in.json new file mode 100644 index 0000000..62a7caa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EXG3/in.json @@ -0,0 +1 @@ +"---word1 word2" diff --git a/Tests/Fixtures/yaml-test-suite/EXG3/in.yaml b/Tests/Fixtures/yaml-test-suite/EXG3/in.yaml new file mode 100644 index 0000000..8ebd5d2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EXG3/in.yaml @@ -0,0 +1,3 @@ +--- +---word1 +word2 diff --git a/Tests/Fixtures/yaml-test-suite/EXG3/test.event b/Tests/Fixtures/yaml-test-suite/EXG3/test.event new file mode 100644 index 0000000..a7881d0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/EXG3/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :---word1 word2 +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/F2C7/in.json b/Tests/Fixtures/yaml-test-suite/F2C7/in.json new file mode 100644 index 0000000..2c185ac --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F2C7/in.json @@ -0,0 +1,6 @@ +[ + "a", + 2, + 4, + "d" +] diff --git a/Tests/Fixtures/yaml-test-suite/F2C7/in.yaml b/Tests/Fixtures/yaml-test-suite/F2C7/in.yaml new file mode 100644 index 0000000..8574f95 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F2C7/in.yaml @@ -0,0 +1,4 @@ + - &a !!str a + - !!int 2 + - !!int &c 4 + - &d d diff --git a/Tests/Fixtures/yaml-test-suite/F2C7/test.event b/Tests/Fixtures/yaml-test-suite/F2C7/test.event new file mode 100644 index 0000000..de11622 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F2C7/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ +=VAL &a :a +=VAL :2 +=VAL &c :4 +=VAL &d :d +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/F3CP/in.json b/Tests/Fixtures/yaml-test-suite/F3CP/in.json new file mode 100644 index 0000000..a134c8f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F3CP/in.json @@ -0,0 +1,12 @@ +{ + "a": [ + "b", + "c", + { + "d": [ + "e", + "f" + ] + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/F3CP/in.yaml b/Tests/Fixtures/yaml-test-suite/F3CP/in.yaml new file mode 100644 index 0000000..04e631b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F3CP/in.yaml @@ -0,0 +1,2 @@ +--- +{ a: [b, c, { d: [e, f] } ] } diff --git a/Tests/Fixtures/yaml-test-suite/F3CP/test.event b/Tests/Fixtures/yaml-test-suite/F3CP/test.event new file mode 100644 index 0000000..8c78aea --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F3CP/test.event @@ -0,0 +1,18 @@ ++STR ++DOC --- ++MAP {} +=VAL :a ++SEQ [] +=VAL :b +=VAL :c ++MAP {} +=VAL :d ++SEQ [] +=VAL :e +=VAL :f +-SEQ +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/F6MC/in.json b/Tests/Fixtures/yaml-test-suite/F6MC/in.json new file mode 100644 index 0000000..72be982 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F6MC/in.json @@ -0,0 +1,4 @@ +{ + "a": " more indented\nregular\n", + "b": "\n\n more indented\nregular\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/F6MC/in.yaml b/Tests/Fixtures/yaml-test-suite/F6MC/in.yaml new file mode 100644 index 0000000..08c530d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F6MC/in.yaml @@ -0,0 +1,9 @@ +--- +a: >2 + more indented + regular +b: >2 + + + more indented + regular diff --git a/Tests/Fixtures/yaml-test-suite/F6MC/test.event b/Tests/Fixtures/yaml-test-suite/F6MC/test.event new file mode 100644 index 0000000..d489359 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F6MC/test.event @@ -0,0 +1,10 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL > more indented\nregular\n +=VAL :b +=VAL >\n\n more indented\nregular\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/F8F9/in.json b/Tests/Fixtures/yaml-test-suite/F8F9/in.json new file mode 100644 index 0000000..4dfaa4e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F8F9/in.json @@ -0,0 +1,5 @@ +{ + "strip": "# text", + "clip": "# text\n", + "keep": "# text\n\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/F8F9/in.yaml b/Tests/Fixtures/yaml-test-suite/F8F9/in.yaml new file mode 100644 index 0000000..32fa08f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F8F9/in.yaml @@ -0,0 +1,19 @@ + # Strip + # Comments: +strip: |- + # text + + # Clip + # comments: + +clip: | + # text + + # Keep + # comments: + +keep: |+ + # text + + # Trail + # comments. diff --git a/Tests/Fixtures/yaml-test-suite/F8F9/test.event b/Tests/Fixtures/yaml-test-suite/F8F9/test.event new file mode 100644 index 0000000..ac535f3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/F8F9/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :strip +=VAL |# text +=VAL :clip +=VAL |# text\n +=VAL :keep +=VAL |# text\n\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/FBC9/in.json b/Tests/Fixtures/yaml-test-suite/FBC9/in.json new file mode 100644 index 0000000..bb25484 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FBC9/in.json @@ -0,0 +1,6 @@ +{ + "safe": "a!\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~ !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~", + "safe question mark": "?foo", + "safe colon": ":foo", + "safe dash": "-foo" +} diff --git a/Tests/Fixtures/yaml-test-suite/FBC9/in.yaml b/Tests/Fixtures/yaml-test-suite/FBC9/in.yaml new file mode 100644 index 0000000..ed2516d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FBC9/in.yaml @@ -0,0 +1,5 @@ +safe: a!"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~ + !"#$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~ +safe question mark: ?foo +safe colon: :foo +safe dash: -foo diff --git a/Tests/Fixtures/yaml-test-suite/FBC9/test.event b/Tests/Fixtures/yaml-test-suite/FBC9/test.event new file mode 100644 index 0000000..e2d5565 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FBC9/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :safe +=VAL :a!"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~ !"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~ +=VAL :safe question mark +=VAL :?foo +=VAL :safe colon +=VAL ::foo +=VAL :safe dash +=VAL :-foo +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/FH7J/in.yaml b/Tests/Fixtures/yaml-test-suite/FH7J/in.yaml new file mode 100644 index 0000000..2b07b28 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FH7J/in.yaml @@ -0,0 +1,5 @@ +- !!str +- + !!null : a + b: !!str +- !!str : !!null diff --git a/Tests/Fixtures/yaml-test-suite/FH7J/test.event b/Tests/Fixtures/yaml-test-suite/FH7J/test.event new file mode 100644 index 0000000..7cac44d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FH7J/test.event @@ -0,0 +1,17 @@ ++STR ++DOC ++SEQ +=VAL : ++MAP +=VAL : +=VAL :a +=VAL :b +=VAL : +-MAP ++MAP +=VAL : +=VAL : +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/FP8R/in.json b/Tests/Fixtures/yaml-test-suite/FP8R/in.json new file mode 100644 index 0000000..15c6a36 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FP8R/in.json @@ -0,0 +1 @@ +"line1 line2 line3\n" diff --git a/Tests/Fixtures/yaml-test-suite/FP8R/in.yaml b/Tests/Fixtures/yaml-test-suite/FP8R/in.yaml new file mode 100644 index 0000000..b4e414d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FP8R/in.yaml @@ -0,0 +1,4 @@ +--- > +line1 +line2 +line3 diff --git a/Tests/Fixtures/yaml-test-suite/FP8R/test.event b/Tests/Fixtures/yaml-test-suite/FP8R/test.event new file mode 100644 index 0000000..7b00b18 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FP8R/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL >line1 line2 line3\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/FQ7F/in.json b/Tests/Fixtures/yaml-test-suite/FQ7F/in.json new file mode 100644 index 0000000..5f8dd7d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FQ7F/in.json @@ -0,0 +1,5 @@ +[ + "Mark McGwire", + "Sammy Sosa", + "Ken Griffey" +] diff --git a/Tests/Fixtures/yaml-test-suite/FQ7F/in.yaml b/Tests/Fixtures/yaml-test-suite/FQ7F/in.yaml new file mode 100644 index 0000000..d12e671 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FQ7F/in.yaml @@ -0,0 +1,3 @@ +- Mark McGwire +- Sammy Sosa +- Ken Griffey diff --git a/Tests/Fixtures/yaml-test-suite/FQ7F/test.event b/Tests/Fixtures/yaml-test-suite/FQ7F/test.event new file mode 100644 index 0000000..006b49d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FQ7F/test.event @@ -0,0 +1,9 @@ ++STR ++DOC ++SEQ +=VAL :Mark McGwire +=VAL :Sammy Sosa +=VAL :Ken Griffey +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/FRK4/in.yaml b/Tests/Fixtures/yaml-test-suite/FRK4/in.yaml new file mode 100644 index 0000000..f46900d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FRK4/in.yaml @@ -0,0 +1,4 @@ +{ + ? foo :, + : bar, +} diff --git a/Tests/Fixtures/yaml-test-suite/FRK4/test.event b/Tests/Fixtures/yaml-test-suite/FRK4/test.event new file mode 100644 index 0000000..870e6c6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FRK4/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP {} +=VAL :foo +=VAL : +=VAL : +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/FTA2/in.json b/Tests/Fixtures/yaml-test-suite/FTA2/in.json new file mode 100644 index 0000000..0ede90f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FTA2/in.json @@ -0,0 +1,3 @@ +[ + "a" +] diff --git a/Tests/Fixtures/yaml-test-suite/FTA2/in.yaml b/Tests/Fixtures/yaml-test-suite/FTA2/in.yaml new file mode 100644 index 0000000..e90e1c7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FTA2/in.yaml @@ -0,0 +1,2 @@ +--- &sequence +- a diff --git a/Tests/Fixtures/yaml-test-suite/FTA2/test.event b/Tests/Fixtures/yaml-test-suite/FTA2/test.event new file mode 100644 index 0000000..8d95a4c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FTA2/test.event @@ -0,0 +1,7 @@ ++STR ++DOC --- ++SEQ &sequence +=VAL :a +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/FUP4/in.json b/Tests/Fixtures/yaml-test-suite/FUP4/in.json new file mode 100644 index 0000000..8b0e4ac --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FUP4/in.json @@ -0,0 +1,7 @@ +[ + "a", + [ + "b", + "c" + ] +] diff --git a/Tests/Fixtures/yaml-test-suite/FUP4/in.yaml b/Tests/Fixtures/yaml-test-suite/FUP4/in.yaml new file mode 100644 index 0000000..5f76a2e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FUP4/in.yaml @@ -0,0 +1 @@ +[a, [b, c]] diff --git a/Tests/Fixtures/yaml-test-suite/FUP4/test.event b/Tests/Fixtures/yaml-test-suite/FUP4/test.event new file mode 100644 index 0000000..b25bde4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/FUP4/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++SEQ [] +=VAL :a ++SEQ [] +=VAL :b +=VAL :c +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/G4RS/in.json b/Tests/Fixtures/yaml-test-suite/G4RS/in.json new file mode 100644 index 0000000..9b2b73a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G4RS/in.json @@ -0,0 +1,8 @@ +{ + "unicode": "Sosa did fine.☺", + "control": "\b1998\t1999\t2000\n", + "hex esc": "\r\n is \r\n", + "single": "\"Howdy!\" he cried.", + "quoted": " # Not a 'comment'.", + "tie-fighter": "|\\-*-/|" +} diff --git a/Tests/Fixtures/yaml-test-suite/G4RS/in.yaml b/Tests/Fixtures/yaml-test-suite/G4RS/in.yaml new file mode 100644 index 0000000..c5c2a18 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G4RS/in.yaml @@ -0,0 +1,7 @@ +unicode: "Sosa did fine.\u263A" +control: "\b1998\t1999\t2000\n" +hex esc: "\x0d\x0a is \r\n" + +single: '"Howdy!" he cried.' +quoted: ' # Not a ''comment''.' +tie-fighter: '|\-*-/|' diff --git a/Tests/Fixtures/yaml-test-suite/G4RS/test.event b/Tests/Fixtures/yaml-test-suite/G4RS/test.event new file mode 100644 index 0000000..6a8a87a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G4RS/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++MAP +=VAL :unicode +=VAL "Sosa did fine.☺ +=VAL :control +=VAL "\b1998\t1999\t2000\n +=VAL :hex esc +=VAL "\r\n is \r\n +=VAL :single +=VAL '"Howdy!" he cried. +=VAL :quoted +=VAL ' # Not a 'comment'. +=VAL :tie-fighter +=VAL '|\\-*-/| +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/G5U8/error b/Tests/Fixtures/yaml-test-suite/G5U8/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/G5U8/in.yaml b/Tests/Fixtures/yaml-test-suite/G5U8/in.yaml new file mode 100644 index 0000000..2af57e7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G5U8/in.yaml @@ -0,0 +1,2 @@ +--- +- [-, -] diff --git a/Tests/Fixtures/yaml-test-suite/G5U8/test.event b/Tests/Fixtures/yaml-test-suite/G5U8/test.event new file mode 100644 index 0000000..a84b729 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G5U8/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/G7JE/error b/Tests/Fixtures/yaml-test-suite/G7JE/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/G7JE/in.yaml b/Tests/Fixtures/yaml-test-suite/G7JE/in.yaml new file mode 100644 index 0000000..e0a85bf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G7JE/in.yaml @@ -0,0 +1,3 @@ +a\nb: 1 +c + d: 1 diff --git a/Tests/Fixtures/yaml-test-suite/G7JE/test.event b/Tests/Fixtures/yaml-test-suite/G7JE/test.event new file mode 100644 index 0000000..d264b4c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G7JE/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :a\\nb +=VAL :1 diff --git a/Tests/Fixtures/yaml-test-suite/G992/in.json b/Tests/Fixtures/yaml-test-suite/G992/in.json new file mode 100644 index 0000000..d5cf354 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G992/in.json @@ -0,0 +1 @@ +"folded text\n" diff --git a/Tests/Fixtures/yaml-test-suite/G992/in.yaml b/Tests/Fixtures/yaml-test-suite/G992/in.yaml new file mode 100644 index 0000000..078fbc8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G992/in.yaml @@ -0,0 +1,5 @@ +> + folded + text + + diff --git a/Tests/Fixtures/yaml-test-suite/G992/test.event b/Tests/Fixtures/yaml-test-suite/G992/test.event new file mode 100644 index 0000000..4e566a5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G992/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL >folded text\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/G9HC/error b/Tests/Fixtures/yaml-test-suite/G9HC/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/G9HC/in.yaml b/Tests/Fixtures/yaml-test-suite/G9HC/in.yaml new file mode 100644 index 0000000..8525992 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G9HC/in.yaml @@ -0,0 +1,5 @@ +--- +seq: +&anchor +- a +- b diff --git a/Tests/Fixtures/yaml-test-suite/G9HC/test.event b/Tests/Fixtures/yaml-test-suite/G9HC/test.event new file mode 100644 index 0000000..d502457 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/G9HC/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :seq diff --git a/Tests/Fixtures/yaml-test-suite/GDY7/error b/Tests/Fixtures/yaml-test-suite/GDY7/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/GDY7/in.yaml b/Tests/Fixtures/yaml-test-suite/GDY7/in.yaml new file mode 100644 index 0000000..ac493b7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/GDY7/in.yaml @@ -0,0 +1,2 @@ +key: value +this is #not a: key diff --git a/Tests/Fixtures/yaml-test-suite/GDY7/test.event b/Tests/Fixtures/yaml-test-suite/GDY7/test.event new file mode 100644 index 0000000..3703456 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/GDY7/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :key +=VAL :value diff --git a/Tests/Fixtures/yaml-test-suite/GH63/in.json b/Tests/Fixtures/yaml-test-suite/GH63/in.json new file mode 100644 index 0000000..649f5e4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/GH63/in.json @@ -0,0 +1,4 @@ +{ + "a": 1.3, + "fifteen": "d" +} diff --git a/Tests/Fixtures/yaml-test-suite/GH63/in.yaml b/Tests/Fixtures/yaml-test-suite/GH63/in.yaml new file mode 100644 index 0000000..e54cd41 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/GH63/in.yaml @@ -0,0 +1,3 @@ +? a +: 1.3 +fifteen: d diff --git a/Tests/Fixtures/yaml-test-suite/GH63/test.event b/Tests/Fixtures/yaml-test-suite/GH63/test.event new file mode 100644 index 0000000..b216b47 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/GH63/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL :1.3 +=VAL :fifteen +=VAL :d +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/GT5M/error b/Tests/Fixtures/yaml-test-suite/GT5M/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/GT5M/in.yaml b/Tests/Fixtures/yaml-test-suite/GT5M/in.yaml new file mode 100644 index 0000000..d641a43 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/GT5M/in.yaml @@ -0,0 +1,3 @@ +- item1 +&node +- item2 diff --git a/Tests/Fixtures/yaml-test-suite/GT5M/test.event b/Tests/Fixtures/yaml-test-suite/GT5M/test.event new file mode 100644 index 0000000..d30c32d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/GT5M/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ +=VAL :item1 diff --git a/Tests/Fixtures/yaml-test-suite/H2RW/in.json b/Tests/Fixtures/yaml-test-suite/H2RW/in.json new file mode 100644 index 0000000..6a308c5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H2RW/in.json @@ -0,0 +1,5 @@ +{ + "foo": 1, + "bar": 2, + "text": "a\n \nb\n\nc\n\nd\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/H2RW/in.yaml b/Tests/Fixtures/yaml-test-suite/H2RW/in.yaml new file mode 100644 index 0000000..4987de2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H2RW/in.yaml @@ -0,0 +1,12 @@ +foo: 1 + +bar: 2 + +text: | + a + + b + + c + + d diff --git a/Tests/Fixtures/yaml-test-suite/H2RW/test.event b/Tests/Fixtures/yaml-test-suite/H2RW/test.event new file mode 100644 index 0000000..836ca98 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H2RW/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :1 +=VAL :bar +=VAL :2 +=VAL :text +=VAL |a\n \nb\n\nc\n\nd\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/H3Z8/in.json b/Tests/Fixtures/yaml-test-suite/H3Z8/in.json new file mode 100644 index 0000000..52e666b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H3Z8/in.json @@ -0,0 +1,3 @@ +{ + "wanted": "love ♥ and peace ☮" +} diff --git a/Tests/Fixtures/yaml-test-suite/H3Z8/in.yaml b/Tests/Fixtures/yaml-test-suite/H3Z8/in.yaml new file mode 100644 index 0000000..3cf0d46 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H3Z8/in.yaml @@ -0,0 +1,2 @@ +--- +wanted: love ♥ and peace ☮ diff --git a/Tests/Fixtures/yaml-test-suite/H3Z8/test.event b/Tests/Fixtures/yaml-test-suite/H3Z8/test.event new file mode 100644 index 0000000..817ac52 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H3Z8/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :wanted +=VAL :love ♥ and peace ☮ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/H7J7/error b/Tests/Fixtures/yaml-test-suite/H7J7/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/H7J7/in.yaml b/Tests/Fixtures/yaml-test-suite/H7J7/in.yaml new file mode 100644 index 0000000..2670fee --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H7J7/in.yaml @@ -0,0 +1,3 @@ +key: &x +!!map + a: b diff --git a/Tests/Fixtures/yaml-test-suite/H7J7/test.event b/Tests/Fixtures/yaml-test-suite/H7J7/test.event new file mode 100644 index 0000000..5727622 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H7J7/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :key +=VAL &x : diff --git a/Tests/Fixtures/yaml-test-suite/H7TQ/error b/Tests/Fixtures/yaml-test-suite/H7TQ/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/H7TQ/in.yaml b/Tests/Fixtures/yaml-test-suite/H7TQ/in.yaml new file mode 100644 index 0000000..79aadcd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H7TQ/in.yaml @@ -0,0 +1,2 @@ +%YAML 1.2 foo +--- diff --git a/Tests/Fixtures/yaml-test-suite/H7TQ/test.event b/Tests/Fixtures/yaml-test-suite/H7TQ/test.event new file mode 100644 index 0000000..e72d602 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/H7TQ/test.event @@ -0,0 +1 @@ ++STR diff --git a/Tests/Fixtures/yaml-test-suite/HM87/00/in.json b/Tests/Fixtures/yaml-test-suite/HM87/00/in.json new file mode 100644 index 0000000..9959ccb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HM87/00/in.json @@ -0,0 +1,3 @@ +[ + ":x" +] diff --git a/Tests/Fixtures/yaml-test-suite/HM87/00/in.yaml b/Tests/Fixtures/yaml-test-suite/HM87/00/in.yaml new file mode 100644 index 0000000..7b8d05b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HM87/00/in.yaml @@ -0,0 +1 @@ +[:x] diff --git a/Tests/Fixtures/yaml-test-suite/HM87/00/test.event b/Tests/Fixtures/yaml-test-suite/HM87/00/test.event new file mode 100644 index 0000000..2a9c4cd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HM87/00/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ [] +=VAL ::x +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/HM87/01/in.json b/Tests/Fixtures/yaml-test-suite/HM87/01/in.json new file mode 100644 index 0000000..8150f2c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HM87/01/in.json @@ -0,0 +1,3 @@ +[ + "?x" +] diff --git a/Tests/Fixtures/yaml-test-suite/HM87/01/in.yaml b/Tests/Fixtures/yaml-test-suite/HM87/01/in.yaml new file mode 100644 index 0000000..d52c931 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HM87/01/in.yaml @@ -0,0 +1 @@ +[?x] diff --git a/Tests/Fixtures/yaml-test-suite/HM87/01/test.event b/Tests/Fixtures/yaml-test-suite/HM87/01/test.event new file mode 100644 index 0000000..14bab5f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HM87/01/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ [] +=VAL :?x +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/HMK4/in.json b/Tests/Fixtures/yaml-test-suite/HMK4/in.json new file mode 100644 index 0000000..e1887b5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HMK4/in.json @@ -0,0 +1,5 @@ +{ + "name": "Mark McGwire", + "accomplishment": "Mark set a major league home run record in 1998.\n", + "stats": "65 Home Runs\n0.278 Batting Average\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/HMK4/in.yaml b/Tests/Fixtures/yaml-test-suite/HMK4/in.yaml new file mode 100644 index 0000000..9f66d88 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HMK4/in.yaml @@ -0,0 +1,7 @@ +name: Mark McGwire +accomplishment: > + Mark set a major league + home run record in 1998. +stats: | + 65 Home Runs + 0.278 Batting Average diff --git a/Tests/Fixtures/yaml-test-suite/HMK4/test.event b/Tests/Fixtures/yaml-test-suite/HMK4/test.event new file mode 100644 index 0000000..c3ae8c2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HMK4/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :name +=VAL :Mark McGwire +=VAL :accomplishment +=VAL >Mark set a major league home run record in 1998.\n +=VAL :stats +=VAL |65 Home Runs\n0.278 Batting Average\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/HMQ5/in.json b/Tests/Fixtures/yaml-test-suite/HMQ5/in.json new file mode 100644 index 0000000..510c6a7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HMQ5/in.json @@ -0,0 +1,4 @@ +{ + "foo": "bar", + "baz": "foo" +} diff --git a/Tests/Fixtures/yaml-test-suite/HMQ5/in.yaml b/Tests/Fixtures/yaml-test-suite/HMQ5/in.yaml new file mode 100644 index 0000000..66d75f3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HMQ5/in.yaml @@ -0,0 +1,3 @@ +!!str &a1 "foo": + !!str bar +&a2 baz : *a1 diff --git a/Tests/Fixtures/yaml-test-suite/HMQ5/test.event b/Tests/Fixtures/yaml-test-suite/HMQ5/test.event new file mode 100644 index 0000000..da6211d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HMQ5/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL &a1 "foo +=VAL :bar +=VAL &a2 :baz +=ALI *a1 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/HRE5/error b/Tests/Fixtures/yaml-test-suite/HRE5/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/HRE5/in.yaml b/Tests/Fixtures/yaml-test-suite/HRE5/in.yaml new file mode 100644 index 0000000..bee64c1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HRE5/in.yaml @@ -0,0 +1,2 @@ +--- +double: "quoted \' scalar" diff --git a/Tests/Fixtures/yaml-test-suite/HRE5/test.event b/Tests/Fixtures/yaml-test-suite/HRE5/test.event new file mode 100644 index 0000000..22055aa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HRE5/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :double diff --git a/Tests/Fixtures/yaml-test-suite/HS5T/in.json b/Tests/Fixtures/yaml-test-suite/HS5T/in.json new file mode 100644 index 0000000..2dc1d4e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HS5T/in.json @@ -0,0 +1 @@ +"1st non-empty\n2nd non-empty 3rd non-empty" diff --git a/Tests/Fixtures/yaml-test-suite/HS5T/in.yaml b/Tests/Fixtures/yaml-test-suite/HS5T/in.yaml new file mode 100644 index 0000000..0499250 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HS5T/in.yaml @@ -0,0 +1,4 @@ +1st non-empty + + 2nd non-empty + 3rd non-empty diff --git a/Tests/Fixtures/yaml-test-suite/HS5T/test.event b/Tests/Fixtures/yaml-test-suite/HS5T/test.event new file mode 100644 index 0000000..505bd4c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HS5T/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL :1st non-empty\n2nd non-empty 3rd non-empty +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/HU3P/error b/Tests/Fixtures/yaml-test-suite/HU3P/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/HU3P/in.yaml b/Tests/Fixtures/yaml-test-suite/HU3P/in.yaml new file mode 100644 index 0000000..d512120 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HU3P/in.yaml @@ -0,0 +1,3 @@ +key: + word1 word2 + no: key diff --git a/Tests/Fixtures/yaml-test-suite/HU3P/test.event b/Tests/Fixtures/yaml-test-suite/HU3P/test.event new file mode 100644 index 0000000..174e371 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HU3P/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :key diff --git a/Tests/Fixtures/yaml-test-suite/HWV9/in.json b/Tests/Fixtures/yaml-test-suite/HWV9/in.json new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/HWV9/in.yaml b/Tests/Fixtures/yaml-test-suite/HWV9/in.yaml new file mode 100644 index 0000000..eb1ae45 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HWV9/in.yaml @@ -0,0 +1 @@ +... diff --git a/Tests/Fixtures/yaml-test-suite/HWV9/test.event b/Tests/Fixtures/yaml-test-suite/HWV9/test.event new file mode 100644 index 0000000..a8c0574 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/HWV9/test.event @@ -0,0 +1,2 @@ ++STR +-STR diff --git a/Tests/Fixtures/yaml-test-suite/J3BT/in.json b/Tests/Fixtures/yaml-test-suite/J3BT/in.json new file mode 100644 index 0000000..5072b48 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J3BT/in.json @@ -0,0 +1,4 @@ +{ + "quoted": "Quoted \t", + "block": "void main() {\n\tprintf(\"Hello, world!\\n\");\n}\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/J3BT/in.yaml b/Tests/Fixtures/yaml-test-suite/J3BT/in.yaml new file mode 100644 index 0000000..af9a321 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J3BT/in.yaml @@ -0,0 +1,6 @@ +# Tabs and spaces +quoted: "Quoted " +block: | + void main() { + printf("Hello, world!\n"); + } diff --git a/Tests/Fixtures/yaml-test-suite/J3BT/test.event b/Tests/Fixtures/yaml-test-suite/J3BT/test.event new file mode 100644 index 0000000..d2a82f5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J3BT/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :quoted +=VAL "Quoted \t +=VAL :block +=VAL |void main() {\n\tprintf("Hello, world!\\n");\n}\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/J5UC/in.json b/Tests/Fixtures/yaml-test-suite/J5UC/in.json new file mode 100644 index 0000000..1d2cefe --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J5UC/in.json @@ -0,0 +1,5 @@ +{ + "foo": "blue", + "bar": "arrr", + "baz": "jazz" +} diff --git a/Tests/Fixtures/yaml-test-suite/J5UC/in.yaml b/Tests/Fixtures/yaml-test-suite/J5UC/in.yaml new file mode 100644 index 0000000..a40b18e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J5UC/in.yaml @@ -0,0 +1,3 @@ +foo: blue +bar: arrr +baz: jazz diff --git a/Tests/Fixtures/yaml-test-suite/J5UC/test.event b/Tests/Fixtures/yaml-test-suite/J5UC/test.event new file mode 100644 index 0000000..0c3b96f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J5UC/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL :blue +=VAL :bar +=VAL :arrr +=VAL :baz +=VAL :jazz +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/J7PZ/in.json b/Tests/Fixtures/yaml-test-suite/J7PZ/in.json new file mode 100644 index 0000000..c5ae8a0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J7PZ/in.json @@ -0,0 +1,11 @@ +[ + { + "Mark McGwire": 65 + }, + { + "Sammy Sosa": 63 + }, + { + "Ken Griffy": 58 + } +] diff --git a/Tests/Fixtures/yaml-test-suite/J7PZ/in.yaml b/Tests/Fixtures/yaml-test-suite/J7PZ/in.yaml new file mode 100644 index 0000000..25692f4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J7PZ/in.yaml @@ -0,0 +1,11 @@ +# The !!omap tag is one of the optional types +# introduced for YAML 1.1. In 1.2, it is not +# part of the standard tags and should not be +# enabled by default. +# Ordered maps are represented as +# A sequence of mappings, with +# each mapping having one key +--- !!omap +- Mark McGwire: 65 +- Sammy Sosa: 63 +- Ken Griffy: 58 diff --git a/Tests/Fixtures/yaml-test-suite/J7PZ/test.event b/Tests/Fixtures/yaml-test-suite/J7PZ/test.event new file mode 100644 index 0000000..264d950 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J7PZ/test.event @@ -0,0 +1,18 @@ ++STR ++DOC --- ++SEQ ++MAP +=VAL :Mark McGwire +=VAL :65 +-MAP ++MAP +=VAL :Sammy Sosa +=VAL :63 +-MAP ++MAP +=VAL :Ken Griffy +=VAL :58 +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/J7VC/in.json b/Tests/Fixtures/yaml-test-suite/J7VC/in.json new file mode 100644 index 0000000..d880c33 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J7VC/in.json @@ -0,0 +1,4 @@ +{ + "one": 2, + "three": 4 +} diff --git a/Tests/Fixtures/yaml-test-suite/J7VC/in.yaml b/Tests/Fixtures/yaml-test-suite/J7VC/in.yaml new file mode 100644 index 0000000..47956a8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J7VC/in.yaml @@ -0,0 +1,4 @@ +one: 2 + + +three: 4 diff --git a/Tests/Fixtures/yaml-test-suite/J7VC/test.event b/Tests/Fixtures/yaml-test-suite/J7VC/test.event new file mode 100644 index 0000000..5a56a0a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J7VC/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :one +=VAL :2 +=VAL :three +=VAL :4 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/J9HZ/in.json b/Tests/Fixtures/yaml-test-suite/J9HZ/in.json new file mode 100644 index 0000000..d32dc2f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J9HZ/in.json @@ -0,0 +1,10 @@ +{ + "hr": [ + "Mark McGwire", + "Sammy Sosa" + ], + "rbi": [ + "Sammy Sosa", + "Ken Griffey" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/J9HZ/in.yaml b/Tests/Fixtures/yaml-test-suite/J9HZ/in.yaml new file mode 100644 index 0000000..e264180 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J9HZ/in.yaml @@ -0,0 +1,8 @@ +--- +hr: # 1998 hr ranking + - Mark McGwire + - Sammy Sosa +rbi: + # 1998 rbi ranking + - Sammy Sosa + - Ken Griffey diff --git a/Tests/Fixtures/yaml-test-suite/J9HZ/test.event b/Tests/Fixtures/yaml-test-suite/J9HZ/test.event new file mode 100644 index 0000000..48133de --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/J9HZ/test.event @@ -0,0 +1,16 @@ ++STR ++DOC --- ++MAP +=VAL :hr ++SEQ +=VAL :Mark McGwire +=VAL :Sammy Sosa +-SEQ +=VAL :rbi ++SEQ +=VAL :Sammy Sosa +=VAL :Ken Griffey +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/00/in.json b/Tests/Fixtures/yaml-test-suite/JEF9/00/in.json new file mode 100644 index 0000000..c1d057c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/00/in.json @@ -0,0 +1,3 @@ +[ + "\n\n" +] diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/00/in.yaml b/Tests/Fixtures/yaml-test-suite/JEF9/00/in.yaml new file mode 100644 index 0000000..be41666 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/00/in.yaml @@ -0,0 +1,3 @@ +- |+ + + diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/00/test.event b/Tests/Fixtures/yaml-test-suite/JEF9/00/test.event new file mode 100644 index 0000000..857fe3e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/00/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ +=VAL |\n\n +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/01/in.json b/Tests/Fixtures/yaml-test-suite/JEF9/01/in.json new file mode 100644 index 0000000..a075745 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/01/in.json @@ -0,0 +1,3 @@ +[ + "\n" +] diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/01/in.yaml b/Tests/Fixtures/yaml-test-suite/JEF9/01/in.yaml new file mode 100644 index 0000000..522e56c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/01/in.yaml @@ -0,0 +1,2 @@ +- |+ + diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/01/test.event b/Tests/Fixtures/yaml-test-suite/JEF9/01/test.event new file mode 100644 index 0000000..d5b8147 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/01/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ +=VAL |\n +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/02/in.json b/Tests/Fixtures/yaml-test-suite/JEF9/02/in.json new file mode 100644 index 0000000..a075745 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/02/in.json @@ -0,0 +1,3 @@ +[ + "\n" +] diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/02/in.yaml b/Tests/Fixtures/yaml-test-suite/JEF9/02/in.yaml new file mode 100644 index 0000000..acfa75d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/02/in.yaml @@ -0,0 +1,2 @@ +- |+ + \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/JEF9/02/test.event b/Tests/Fixtures/yaml-test-suite/JEF9/02/test.event new file mode 100644 index 0000000..d5b8147 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JEF9/02/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ +=VAL |\n +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JHB9/in.json b/Tests/Fixtures/yaml-test-suite/JHB9/in.json new file mode 100644 index 0000000..4a96ef4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JHB9/in.json @@ -0,0 +1,9 @@ +[ + "Mark McGwire", + "Sammy Sosa", + "Ken Griffey" +] +[ + "Chicago Cubs", + "St Louis Cardinals" +] diff --git a/Tests/Fixtures/yaml-test-suite/JHB9/in.yaml b/Tests/Fixtures/yaml-test-suite/JHB9/in.yaml new file mode 100644 index 0000000..bc711d5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JHB9/in.yaml @@ -0,0 +1,10 @@ +# Ranking of 1998 home runs +--- +- Mark McGwire +- Sammy Sosa +- Ken Griffey + +# Team ranking +--- +- Chicago Cubs +- St Louis Cardinals diff --git a/Tests/Fixtures/yaml-test-suite/JHB9/test.event b/Tests/Fixtures/yaml-test-suite/JHB9/test.event new file mode 100644 index 0000000..2530a74 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JHB9/test.event @@ -0,0 +1,15 @@ ++STR ++DOC --- ++SEQ +=VAL :Mark McGwire +=VAL :Sammy Sosa +=VAL :Ken Griffey +-SEQ +-DOC ++DOC --- ++SEQ +=VAL :Chicago Cubs +=VAL :St Louis Cardinals +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JKF3/error b/Tests/Fixtures/yaml-test-suite/JKF3/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/JKF3/in.yaml b/Tests/Fixtures/yaml-test-suite/JKF3/in.yaml new file mode 100644 index 0000000..c2718a1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JKF3/in.yaml @@ -0,0 +1,2 @@ +- - "bar +bar": x diff --git a/Tests/Fixtures/yaml-test-suite/JKF3/test.event b/Tests/Fixtures/yaml-test-suite/JKF3/test.event new file mode 100644 index 0000000..487fbbe --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JKF3/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ diff --git a/Tests/Fixtures/yaml-test-suite/JQ4R/in.json b/Tests/Fixtures/yaml-test-suite/JQ4R/in.json new file mode 100644 index 0000000..ad5c054 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JQ4R/in.json @@ -0,0 +1,8 @@ +{ + "block sequence": [ + "one", + { + "two": "three" + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/JQ4R/in.yaml b/Tests/Fixtures/yaml-test-suite/JQ4R/in.yaml new file mode 100644 index 0000000..d2f2ccf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JQ4R/in.yaml @@ -0,0 +1,3 @@ +block sequence: + - one + - two : three diff --git a/Tests/Fixtures/yaml-test-suite/JQ4R/test.event b/Tests/Fixtures/yaml-test-suite/JQ4R/test.event new file mode 100644 index 0000000..513315c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JQ4R/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :block sequence ++SEQ +=VAL :one ++MAP +=VAL :two +=VAL :three +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JR7V/in.json b/Tests/Fixtures/yaml-test-suite/JR7V/in.json new file mode 100644 index 0000000..eba7f7f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JR7V/in.json @@ -0,0 +1,22 @@ +[ + "a?string", + "another ? string", + { + "key": "value?" + }, + [ + "a?string" + ], + [ + "another ? string" + ], + { + "key": "value?" + }, + { + "key": "value?" + }, + { + "key?": "value" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/JR7V/in.yaml b/Tests/Fixtures/yaml-test-suite/JR7V/in.yaml new file mode 100644 index 0000000..c41e47c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JR7V/in.yaml @@ -0,0 +1,8 @@ +- a?string +- another ? string +- key: value? +- [a?string] +- [another ? string] +- {key: value? } +- {key: value?} +- {key?: value } diff --git a/Tests/Fixtures/yaml-test-suite/JR7V/test.event b/Tests/Fixtures/yaml-test-suite/JR7V/test.event new file mode 100644 index 0000000..e04d9c8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JR7V/test.event @@ -0,0 +1,30 @@ ++STR ++DOC ++SEQ +=VAL :a?string +=VAL :another ? string ++MAP +=VAL :key +=VAL :value? +-MAP ++SEQ [] +=VAL :a?string +-SEQ ++SEQ [] +=VAL :another ? string +-SEQ ++MAP {} +=VAL :key +=VAL :value? +-MAP ++MAP {} +=VAL :key +=VAL :value? +-MAP ++MAP {} +=VAL :key? +=VAL :value +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JS2J/in.json b/Tests/Fixtures/yaml-test-suite/JS2J/in.json new file mode 100644 index 0000000..4b838cf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JS2J/in.json @@ -0,0 +1,4 @@ +{ + "First occurrence": "Value", + "Second occurrence": "Value" +} diff --git a/Tests/Fixtures/yaml-test-suite/JS2J/in.yaml b/Tests/Fixtures/yaml-test-suite/JS2J/in.yaml new file mode 100644 index 0000000..600d179 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JS2J/in.yaml @@ -0,0 +1,2 @@ +First occurrence: &anchor Value +Second occurrence: *anchor diff --git a/Tests/Fixtures/yaml-test-suite/JS2J/test.event b/Tests/Fixtures/yaml-test-suite/JS2J/test.event new file mode 100644 index 0000000..6086bba --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JS2J/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :First occurrence +=VAL &anchor :Value +=VAL :Second occurrence +=ALI *anchor +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JTV5/in.json b/Tests/Fixtures/yaml-test-suite/JTV5/in.json new file mode 100644 index 0000000..fbccf11 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JTV5/in.json @@ -0,0 +1,4 @@ +{ + "a true": "null d", + "e 42": null +} diff --git a/Tests/Fixtures/yaml-test-suite/JTV5/in.yaml b/Tests/Fixtures/yaml-test-suite/JTV5/in.yaml new file mode 100644 index 0000000..247a8cd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JTV5/in.yaml @@ -0,0 +1,6 @@ +? a + true +: null + d +? e + 42 diff --git a/Tests/Fixtures/yaml-test-suite/JTV5/test.event b/Tests/Fixtures/yaml-test-suite/JTV5/test.event new file mode 100644 index 0000000..cd34334 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JTV5/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :a true +=VAL :null d +=VAL :e 42 +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/JY7Z/error b/Tests/Fixtures/yaml-test-suite/JY7Z/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/JY7Z/in.yaml b/Tests/Fixtures/yaml-test-suite/JY7Z/in.yaml new file mode 100644 index 0000000..8554678 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JY7Z/in.yaml @@ -0,0 +1,3 @@ +key1: "quoted1" +key2: "quoted2" no key: nor value +key3: "quoted3" diff --git a/Tests/Fixtures/yaml-test-suite/JY7Z/test.event b/Tests/Fixtures/yaml-test-suite/JY7Z/test.event new file mode 100644 index 0000000..128a5c5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/JY7Z/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++MAP +=VAL :key1 +=VAL "quoted1 +=VAL :key2 +=VAL "quoted2 diff --git a/Tests/Fixtures/yaml-test-suite/K3WX/in.json b/Tests/Fixtures/yaml-test-suite/K3WX/in.json new file mode 100644 index 0000000..c8c4105 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K3WX/in.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/K3WX/in.yaml b/Tests/Fixtures/yaml-test-suite/K3WX/in.yaml new file mode 100644 index 0000000..14d2753 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K3WX/in.yaml @@ -0,0 +1,3 @@ +--- +{ "foo" # comment + :bar } diff --git a/Tests/Fixtures/yaml-test-suite/K3WX/test.event b/Tests/Fixtures/yaml-test-suite/K3WX/test.event new file mode 100644 index 0000000..fd46afc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K3WX/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP {} +=VAL "foo +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/K4SU/in.json b/Tests/Fixtures/yaml-test-suite/K4SU/in.json new file mode 100644 index 0000000..1866413 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K4SU/in.json @@ -0,0 +1,5 @@ +[ + "foo", + "bar", + 42 +] diff --git a/Tests/Fixtures/yaml-test-suite/K4SU/in.yaml b/Tests/Fixtures/yaml-test-suite/K4SU/in.yaml new file mode 100644 index 0000000..5fae9f4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K4SU/in.yaml @@ -0,0 +1,3 @@ +- foo +- bar +- 42 diff --git a/Tests/Fixtures/yaml-test-suite/K4SU/test.event b/Tests/Fixtures/yaml-test-suite/K4SU/test.event new file mode 100644 index 0000000..4bdcfec --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K4SU/test.event @@ -0,0 +1,9 @@ ++STR ++DOC ++SEQ +=VAL :foo +=VAL :bar +=VAL :42 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/K527/in.json b/Tests/Fixtures/yaml-test-suite/K527/in.json new file mode 100644 index 0000000..9c6ce92 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K527/in.json @@ -0,0 +1 @@ +"trimmed\n\n\nas space" diff --git a/Tests/Fixtures/yaml-test-suite/K527/in.yaml b/Tests/Fixtures/yaml-test-suite/K527/in.yaml new file mode 100644 index 0000000..1c5090d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K527/in.yaml @@ -0,0 +1,7 @@ +>- + trimmed + + + + as + space diff --git a/Tests/Fixtures/yaml-test-suite/K527/test.event b/Tests/Fixtures/yaml-test-suite/K527/test.event new file mode 100644 index 0000000..8478e52 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K527/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL >trimmed\n\n\nas space +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/K54U/in.json b/Tests/Fixtures/yaml-test-suite/K54U/in.json new file mode 100644 index 0000000..6dbc311 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K54U/in.json @@ -0,0 +1 @@ +"scalar" diff --git a/Tests/Fixtures/yaml-test-suite/K54U/in.yaml b/Tests/Fixtures/yaml-test-suite/K54U/in.yaml new file mode 100644 index 0000000..8171dcc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K54U/in.yaml @@ -0,0 +1 @@ +--- scalar diff --git a/Tests/Fixtures/yaml-test-suite/K54U/test.event b/Tests/Fixtures/yaml-test-suite/K54U/test.event new file mode 100644 index 0000000..7403072 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K54U/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :scalar +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/K858/in.json b/Tests/Fixtures/yaml-test-suite/K858/in.json new file mode 100644 index 0000000..d63b700 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K858/in.json @@ -0,0 +1,5 @@ +{ + "strip": "", + "clip": "", + "keep": "\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/K858/in.yaml b/Tests/Fixtures/yaml-test-suite/K858/in.yaml new file mode 100644 index 0000000..de0b64b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K858/in.yaml @@ -0,0 +1,6 @@ +strip: >- + +clip: > + +keep: |+ + diff --git a/Tests/Fixtures/yaml-test-suite/K858/test.event b/Tests/Fixtures/yaml-test-suite/K858/test.event new file mode 100644 index 0000000..273996c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/K858/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :strip +=VAL > +=VAL :clip +=VAL > +=VAL :keep +=VAL |\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/00/in.json b/Tests/Fixtures/yaml-test-suite/KH5V/00/in.json new file mode 100644 index 0000000..f0458e7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/00/in.json @@ -0,0 +1 @@ +"1 inline\ttab" diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/00/in.yaml b/Tests/Fixtures/yaml-test-suite/KH5V/00/in.yaml new file mode 100644 index 0000000..f0458e7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/00/in.yaml @@ -0,0 +1 @@ +"1 inline\ttab" diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/00/test.event b/Tests/Fixtures/yaml-test-suite/KH5V/00/test.event new file mode 100644 index 0000000..efad6d3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/00/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "1 inline\ttab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/01/in.json b/Tests/Fixtures/yaml-test-suite/KH5V/01/in.json new file mode 100644 index 0000000..0bd18c3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/01/in.json @@ -0,0 +1 @@ +"2 inline\ttab" diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/01/in.yaml b/Tests/Fixtures/yaml-test-suite/KH5V/01/in.yaml new file mode 100644 index 0000000..e32b715 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/01/in.yaml @@ -0,0 +1 @@ +"2 inline\ tab" diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/01/test.event b/Tests/Fixtures/yaml-test-suite/KH5V/01/test.event new file mode 100644 index 0000000..342bb9d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/01/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "2 inline\ttab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/02/in.json b/Tests/Fixtures/yaml-test-suite/KH5V/02/in.json new file mode 100644 index 0000000..a7a0e0f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/02/in.json @@ -0,0 +1 @@ +"3 inline\ttab" diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/02/in.yaml b/Tests/Fixtures/yaml-test-suite/KH5V/02/in.yaml new file mode 100644 index 0000000..ef3075f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/02/in.yaml @@ -0,0 +1 @@ +"3 inline tab" diff --git a/Tests/Fixtures/yaml-test-suite/KH5V/02/test.event b/Tests/Fixtures/yaml-test-suite/KH5V/02/test.event new file mode 100644 index 0000000..b454c7d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KH5V/02/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "3 inline\ttab +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/KK5P/in.yaml b/Tests/Fixtures/yaml-test-suite/KK5P/in.yaml new file mode 100644 index 0000000..872966f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KK5P/in.yaml @@ -0,0 +1,16 @@ +complex1: + ? - a +complex2: + ? - a + : b +complex3: + ? - a + : > + b +complex4: + ? > + a + : +complex5: + ? - a + : - b diff --git a/Tests/Fixtures/yaml-test-suite/KK5P/test.event b/Tests/Fixtures/yaml-test-suite/KK5P/test.event new file mode 100644 index 0000000..197eae8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KK5P/test.event @@ -0,0 +1,41 @@ ++STR ++DOC ++MAP +=VAL :complex1 ++MAP ++SEQ +=VAL :a +-SEQ +=VAL : +-MAP +=VAL :complex2 ++MAP ++SEQ +=VAL :a +-SEQ +=VAL :b +-MAP +=VAL :complex3 ++MAP ++SEQ +=VAL :a +-SEQ +=VAL >b\n +-MAP +=VAL :complex4 ++MAP +=VAL >a\n +=VAL : +-MAP +=VAL :complex5 ++MAP ++SEQ +=VAL :a +-SEQ ++SEQ +=VAL :b +-SEQ +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/KMK3/in.json b/Tests/Fixtures/yaml-test-suite/KMK3/in.json new file mode 100644 index 0000000..b7cf07e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KMK3/in.json @@ -0,0 +1,6 @@ +{ + "foo": { + "bar": 1 + }, + "baz": 2 +} diff --git a/Tests/Fixtures/yaml-test-suite/KMK3/in.yaml b/Tests/Fixtures/yaml-test-suite/KMK3/in.yaml new file mode 100644 index 0000000..32d2114 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KMK3/in.yaml @@ -0,0 +1,3 @@ +foo: + bar: 1 +baz: 2 diff --git a/Tests/Fixtures/yaml-test-suite/KMK3/test.event b/Tests/Fixtures/yaml-test-suite/KMK3/test.event new file mode 100644 index 0000000..f06d65b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KMK3/test.event @@ -0,0 +1,13 @@ ++STR ++DOC ++MAP +=VAL :foo ++MAP +=VAL :bar +=VAL :1 +-MAP +=VAL :baz +=VAL :2 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/KS4U/error b/Tests/Fixtures/yaml-test-suite/KS4U/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/KS4U/in.yaml b/Tests/Fixtures/yaml-test-suite/KS4U/in.yaml new file mode 100644 index 0000000..a77ca09 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KS4U/in.yaml @@ -0,0 +1,5 @@ +--- +[ +sequence item +] +invalid item diff --git a/Tests/Fixtures/yaml-test-suite/KS4U/test.event b/Tests/Fixtures/yaml-test-suite/KS4U/test.event new file mode 100644 index 0000000..10ac38c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KS4U/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- ++SEQ [] +=VAL :sequence item +-SEQ diff --git a/Tests/Fixtures/yaml-test-suite/KSS4/in.json b/Tests/Fixtures/yaml-test-suite/KSS4/in.json new file mode 100644 index 0000000..19747c7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KSS4/in.json @@ -0,0 +1,2 @@ +"quoted string" +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/KSS4/in.yaml b/Tests/Fixtures/yaml-test-suite/KSS4/in.yaml new file mode 100644 index 0000000..5cbbe23 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KSS4/in.yaml @@ -0,0 +1,3 @@ +--- "quoted +string" +--- &node foo diff --git a/Tests/Fixtures/yaml-test-suite/KSS4/test.event b/Tests/Fixtures/yaml-test-suite/KSS4/test.event new file mode 100644 index 0000000..18b9f0f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/KSS4/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- +=VAL "quoted string +-DOC ++DOC --- +=VAL &node :foo +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/L24T/00/in.json b/Tests/Fixtures/yaml-test-suite/L24T/00/in.json new file mode 100644 index 0000000..6548965 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L24T/00/in.json @@ -0,0 +1,3 @@ +{ + "foo" : "x\n \n" +} diff --git a/Tests/Fixtures/yaml-test-suite/L24T/00/in.yaml b/Tests/Fixtures/yaml-test-suite/L24T/00/in.yaml new file mode 100644 index 0000000..6a1854b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L24T/00/in.yaml @@ -0,0 +1,3 @@ +foo: | + x + diff --git a/Tests/Fixtures/yaml-test-suite/L24T/00/test.event b/Tests/Fixtures/yaml-test-suite/L24T/00/test.event new file mode 100644 index 0000000..7f11a30 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L24T/00/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL |x\n \n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/L24T/01/in.json b/Tests/Fixtures/yaml-test-suite/L24T/01/in.json new file mode 100644 index 0000000..6548965 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L24T/01/in.json @@ -0,0 +1,3 @@ +{ + "foo" : "x\n \n" +} diff --git a/Tests/Fixtures/yaml-test-suite/L24T/01/in.yaml b/Tests/Fixtures/yaml-test-suite/L24T/01/in.yaml new file mode 100644 index 0000000..b5768af --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L24T/01/in.yaml @@ -0,0 +1,3 @@ +foo: | + x + \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/L24T/01/test.event b/Tests/Fixtures/yaml-test-suite/L24T/01/test.event new file mode 100644 index 0000000..7f11a30 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L24T/01/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL |x\n \n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/L383/in.json b/Tests/Fixtures/yaml-test-suite/L383/in.json new file mode 100644 index 0000000..d53e1d6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L383/in.json @@ -0,0 +1,2 @@ +"foo" +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/L383/in.yaml b/Tests/Fixtures/yaml-test-suite/L383/in.yaml new file mode 100644 index 0000000..235f249 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L383/in.yaml @@ -0,0 +1,2 @@ +--- foo # comment +--- foo # comment diff --git a/Tests/Fixtures/yaml-test-suite/L383/test.event b/Tests/Fixtures/yaml-test-suite/L383/test.event new file mode 100644 index 0000000..5776a7c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L383/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- +=VAL :foo +-DOC ++DOC --- +=VAL :foo +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/L94M/in.json b/Tests/Fixtures/yaml-test-suite/L94M/in.json new file mode 100644 index 0000000..07ded62 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L94M/in.json @@ -0,0 +1,4 @@ +{ + "a": 47, + "c": "d" +} diff --git a/Tests/Fixtures/yaml-test-suite/L94M/in.yaml b/Tests/Fixtures/yaml-test-suite/L94M/in.yaml new file mode 100644 index 0000000..c5e6ceb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L94M/in.yaml @@ -0,0 +1,4 @@ +? !!str a +: !!int 47 +? c +: !!str d diff --git a/Tests/Fixtures/yaml-test-suite/L94M/test.event b/Tests/Fixtures/yaml-test-suite/L94M/test.event new file mode 100644 index 0000000..e8ed464 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L94M/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL :47 +=VAL :c +=VAL :d +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/L9U5/in.json b/Tests/Fixtures/yaml-test-suite/L9U5/in.json new file mode 100644 index 0000000..16ae65b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L9U5/in.json @@ -0,0 +1,7 @@ +{ + "implicit block key": [ + { + "implicit flow key": "value" + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/L9U5/in.yaml b/Tests/Fixtures/yaml-test-suite/L9U5/in.yaml new file mode 100644 index 0000000..fd57f65 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L9U5/in.yaml @@ -0,0 +1,3 @@ +implicit block key : [ + implicit flow key : value, + ] diff --git a/Tests/Fixtures/yaml-test-suite/L9U5/test.event b/Tests/Fixtures/yaml-test-suite/L9U5/test.event new file mode 100644 index 0000000..7e2a621 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/L9U5/test.event @@ -0,0 +1,13 @@ ++STR ++DOC ++MAP +=VAL :implicit block key ++SEQ [] ++MAP {} +=VAL :implicit flow key +=VAL :value +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/LE5A/in.json b/Tests/Fixtures/yaml-test-suite/LE5A/in.json new file mode 100644 index 0000000..fc128b8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LE5A/in.json @@ -0,0 +1,7 @@ +[ + "a", + "b", + "c", + "c", + "" +] diff --git a/Tests/Fixtures/yaml-test-suite/LE5A/in.yaml b/Tests/Fixtures/yaml-test-suite/LE5A/in.yaml new file mode 100644 index 0000000..db4007f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LE5A/in.yaml @@ -0,0 +1,5 @@ +- !!str "a" +- 'b' +- &anchor "c" +- *anchor +- !!str diff --git a/Tests/Fixtures/yaml-test-suite/LE5A/test.event b/Tests/Fixtures/yaml-test-suite/LE5A/test.event new file mode 100644 index 0000000..2c4e449 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LE5A/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++SEQ +=VAL "a +=VAL 'b +=VAL &anchor "c +=ALI *anchor +=VAL : +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/LHL4/error b/Tests/Fixtures/yaml-test-suite/LHL4/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/LHL4/in.yaml b/Tests/Fixtures/yaml-test-suite/LHL4/in.yaml new file mode 100644 index 0000000..3d0ecf2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LHL4/in.yaml @@ -0,0 +1,2 @@ +--- +!invalid{}tag scalar diff --git a/Tests/Fixtures/yaml-test-suite/LHL4/test.event b/Tests/Fixtures/yaml-test-suite/LHL4/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LHL4/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/LP6E/in.json b/Tests/Fixtures/yaml-test-suite/LP6E/in.json new file mode 100644 index 0000000..178c43c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LP6E/in.json @@ -0,0 +1,13 @@ +[ + [ + "a", + "b", + "c" + ], + { + "a": "b", + "c": "d", + "e": "f" + }, + [] +] diff --git a/Tests/Fixtures/yaml-test-suite/LP6E/in.yaml b/Tests/Fixtures/yaml-test-suite/LP6E/in.yaml new file mode 100644 index 0000000..3a60909 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LP6E/in.yaml @@ -0,0 +1,6 @@ +- [a, b , c ] +- { "a" : b + , c : 'd' , + e : "f" + } +- [ ] diff --git a/Tests/Fixtures/yaml-test-suite/LP6E/test.event b/Tests/Fixtures/yaml-test-suite/LP6E/test.event new file mode 100644 index 0000000..0fb906b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LP6E/test.event @@ -0,0 +1,21 @@ ++STR ++DOC ++SEQ ++SEQ [] +=VAL :a +=VAL :b +=VAL :c +-SEQ ++MAP {} +=VAL "a +=VAL :b +=VAL :c +=VAL 'd +=VAL :e +=VAL "f +-MAP ++SEQ [] +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/LQZ7/in.json b/Tests/Fixtures/yaml-test-suite/LQZ7/in.json new file mode 100644 index 0000000..16ae65b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LQZ7/in.json @@ -0,0 +1,7 @@ +{ + "implicit block key": [ + { + "implicit flow key": "value" + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/LQZ7/in.yaml b/Tests/Fixtures/yaml-test-suite/LQZ7/in.yaml new file mode 100644 index 0000000..1b7a550 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LQZ7/in.yaml @@ -0,0 +1,3 @@ +"implicit block key" : [ + "implicit flow key" : value, + ] diff --git a/Tests/Fixtures/yaml-test-suite/LQZ7/test.event b/Tests/Fixtures/yaml-test-suite/LQZ7/test.event new file mode 100644 index 0000000..25701d2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LQZ7/test.event @@ -0,0 +1,13 @@ ++STR ++DOC ++MAP +=VAL "implicit block key ++SEQ [] ++MAP {} +=VAL "implicit flow key +=VAL :value +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/LX3P/in.yaml b/Tests/Fixtures/yaml-test-suite/LX3P/in.yaml new file mode 100644 index 0000000..b13c841 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LX3P/in.yaml @@ -0,0 +1 @@ +[flow]: block diff --git a/Tests/Fixtures/yaml-test-suite/LX3P/test.event b/Tests/Fixtures/yaml-test-suite/LX3P/test.event new file mode 100644 index 0000000..6358d03 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/LX3P/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP ++SEQ [] +=VAL :flow +-SEQ +=VAL :block +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M29M/in.json b/Tests/Fixtures/yaml-test-suite/M29M/in.json new file mode 100644 index 0000000..093e6e2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M29M/in.json @@ -0,0 +1,3 @@ +{ + "a": "ab\n\ncd\nef\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/M29M/in.yaml b/Tests/Fixtures/yaml-test-suite/M29M/in.yaml new file mode 100644 index 0000000..d472650 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M29M/in.yaml @@ -0,0 +1,8 @@ +a: | + ab + + cd + ef + + +... diff --git a/Tests/Fixtures/yaml-test-suite/M29M/test.event b/Tests/Fixtures/yaml-test-suite/M29M/test.event new file mode 100644 index 0000000..12a9e3b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M29M/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL |ab\n\ncd\nef\n +-MAP +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M2N8/00/in.yaml b/Tests/Fixtures/yaml-test-suite/M2N8/00/in.yaml new file mode 100644 index 0000000..82c9ffa --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M2N8/00/in.yaml @@ -0,0 +1 @@ +- ? : x diff --git a/Tests/Fixtures/yaml-test-suite/M2N8/00/test.event b/Tests/Fixtures/yaml-test-suite/M2N8/00/test.event new file mode 100644 index 0000000..60a5aca --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M2N8/00/test.event @@ -0,0 +1,13 @@ ++STR ++DOC ++SEQ ++MAP ++MAP +=VAL : +=VAL :x +-MAP +=VAL : +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M2N8/01/in.yaml b/Tests/Fixtures/yaml-test-suite/M2N8/01/in.yaml new file mode 100644 index 0000000..a786266 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M2N8/01/in.yaml @@ -0,0 +1 @@ +? []: x diff --git a/Tests/Fixtures/yaml-test-suite/M2N8/01/test.event b/Tests/Fixtures/yaml-test-suite/M2N8/01/test.event new file mode 100644 index 0000000..cc65458 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M2N8/01/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP ++MAP ++SEQ [] +-SEQ +=VAL :x +-MAP +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M5C3/in.json b/Tests/Fixtures/yaml-test-suite/M5C3/in.json new file mode 100644 index 0000000..f1eedb0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M5C3/in.json @@ -0,0 +1,4 @@ +{ + "literal": "value\n", + "folded": "value\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/M5C3/in.yaml b/Tests/Fixtures/yaml-test-suite/M5C3/in.yaml new file mode 100644 index 0000000..f86be74 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M5C3/in.yaml @@ -0,0 +1,6 @@ +literal: |2 + value +folded: + !foo + >1 + value diff --git a/Tests/Fixtures/yaml-test-suite/M5C3/test.event b/Tests/Fixtures/yaml-test-suite/M5C3/test.event new file mode 100644 index 0000000..fcebe87 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M5C3/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :literal +=VAL |value\n +=VAL :folded +=VAL >value\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M5DY/in.yaml b/Tests/Fixtures/yaml-test-suite/M5DY/in.yaml new file mode 100644 index 0000000..9123ce2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M5DY/in.yaml @@ -0,0 +1,9 @@ +? - Detroit Tigers + - Chicago cubs +: + - 2001-07-23 + +? [ New York Yankees, + Atlanta Braves ] +: [ 2001-07-02, 2001-08-12, + 2001-08-14 ] diff --git a/Tests/Fixtures/yaml-test-suite/M5DY/test.event b/Tests/Fixtures/yaml-test-suite/M5DY/test.event new file mode 100644 index 0000000..4362cad --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M5DY/test.event @@ -0,0 +1,22 @@ ++STR ++DOC ++MAP ++SEQ +=VAL :Detroit Tigers +=VAL :Chicago cubs +-SEQ ++SEQ +=VAL :2001-07-23 +-SEQ ++SEQ [] +=VAL :New York Yankees +=VAL :Atlanta Braves +-SEQ ++SEQ [] +=VAL :2001-07-02 +=VAL :2001-08-12 +=VAL :2001-08-14 +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M6YH/in.json b/Tests/Fixtures/yaml-test-suite/M6YH/in.json new file mode 100644 index 0000000..8e9ddf6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M6YH/in.json @@ -0,0 +1,9 @@ +[ + "x\n", + { + "foo" : "bar" + }, + [ + 42 + ] +] diff --git a/Tests/Fixtures/yaml-test-suite/M6YH/in.yaml b/Tests/Fixtures/yaml-test-suite/M6YH/in.yaml new file mode 100644 index 0000000..d8468d7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M6YH/in.yaml @@ -0,0 +1,6 @@ +- | + x +- + foo: bar +- + - 42 diff --git a/Tests/Fixtures/yaml-test-suite/M6YH/test.event b/Tests/Fixtures/yaml-test-suite/M6YH/test.event new file mode 100644 index 0000000..c242b41 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M6YH/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++SEQ +=VAL |x\n ++MAP +=VAL :foo +=VAL :bar +-MAP ++SEQ +=VAL :42 +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M7A3/in.json b/Tests/Fixtures/yaml-test-suite/M7A3/in.json new file mode 100644 index 0000000..7f59d09 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M7A3/in.json @@ -0,0 +1,2 @@ +"Bare document" +"%!PS-Adobe-2.0 # Not the first line\n" diff --git a/Tests/Fixtures/yaml-test-suite/M7A3/in.yaml b/Tests/Fixtures/yaml-test-suite/M7A3/in.yaml new file mode 100644 index 0000000..57423e9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M7A3/in.yaml @@ -0,0 +1,7 @@ +Bare +document +... +# No document +... +| +%!PS-Adobe-2.0 # Not the first line diff --git a/Tests/Fixtures/yaml-test-suite/M7A3/test.event b/Tests/Fixtures/yaml-test-suite/M7A3/test.event new file mode 100644 index 0000000..e3016ea --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M7A3/test.event @@ -0,0 +1,8 @@ ++STR ++DOC +=VAL :Bare document +-DOC ... ++DOC +=VAL |%!PS-Adobe-2.0 # Not the first line\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M7NX/in.json b/Tests/Fixtures/yaml-test-suite/M7NX/in.json new file mode 100644 index 0000000..a134c8f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M7NX/in.json @@ -0,0 +1,12 @@ +{ + "a": [ + "b", + "c", + { + "d": [ + "e", + "f" + ] + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/M7NX/in.yaml b/Tests/Fixtures/yaml-test-suite/M7NX/in.yaml new file mode 100644 index 0000000..d8f46c4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M7NX/in.yaml @@ -0,0 +1,8 @@ +--- +{ + a: [ + b, c, { + d: [e, f] + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/M7NX/test.event b/Tests/Fixtures/yaml-test-suite/M7NX/test.event new file mode 100644 index 0000000..8c78aea --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M7NX/test.event @@ -0,0 +1,18 @@ ++STR ++DOC --- ++MAP {} +=VAL :a ++SEQ [] +=VAL :b +=VAL :c ++MAP {} +=VAL :d ++SEQ [] +=VAL :e +=VAL :f +-SEQ +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/M9B4/in.json b/Tests/Fixtures/yaml-test-suite/M9B4/in.json new file mode 100644 index 0000000..2e190c6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M9B4/in.json @@ -0,0 +1 @@ +"literal\n\ttext\n" diff --git a/Tests/Fixtures/yaml-test-suite/M9B4/in.yaml b/Tests/Fixtures/yaml-test-suite/M9B4/in.yaml new file mode 100644 index 0000000..31f9966 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M9B4/in.yaml @@ -0,0 +1,5 @@ +| + literal + text + + diff --git a/Tests/Fixtures/yaml-test-suite/M9B4/test.event b/Tests/Fixtures/yaml-test-suite/M9B4/test.event new file mode 100644 index 0000000..5d79e04 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/M9B4/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL |literal\n\ttext\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MJS9/in.json b/Tests/Fixtures/yaml-test-suite/MJS9/in.json new file mode 100644 index 0000000..9dd9b03 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MJS9/in.json @@ -0,0 +1 @@ +"foo \n\n\t bar\n\nbaz\n" diff --git a/Tests/Fixtures/yaml-test-suite/MJS9/in.yaml b/Tests/Fixtures/yaml-test-suite/MJS9/in.yaml new file mode 100644 index 0000000..0896cc6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MJS9/in.yaml @@ -0,0 +1,6 @@ +> + foo + + bar + + baz diff --git a/Tests/Fixtures/yaml-test-suite/MJS9/test.event b/Tests/Fixtures/yaml-test-suite/MJS9/test.event new file mode 100644 index 0000000..8fff83e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MJS9/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL >foo \n\n\t bar\n\nbaz\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/00/error b/Tests/Fixtures/yaml-test-suite/MUS6/00/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/00/in.yaml b/Tests/Fixtures/yaml-test-suite/MUS6/00/in.yaml new file mode 100644 index 0000000..bb08497 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/00/in.yaml @@ -0,0 +1,2 @@ +%YAML 1.1#... +--- diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/00/test.event b/Tests/Fixtures/yaml-test-suite/MUS6/00/test.event new file mode 100644 index 0000000..e72d602 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/00/test.event @@ -0,0 +1 @@ ++STR diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/01/error b/Tests/Fixtures/yaml-test-suite/MUS6/01/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/01/in.yaml b/Tests/Fixtures/yaml-test-suite/MUS6/01/in.yaml new file mode 100644 index 0000000..a919837 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/01/in.yaml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +%YAML 1.2 +--- diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/01/test.event b/Tests/Fixtures/yaml-test-suite/MUS6/01/test.event new file mode 100644 index 0000000..e72d602 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/01/test.event @@ -0,0 +1 @@ ++STR diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/02/in.json b/Tests/Fixtures/yaml-test-suite/MUS6/02/in.json new file mode 100644 index 0000000..19765bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/02/in.json @@ -0,0 +1 @@ +null diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/02/in.yaml b/Tests/Fixtures/yaml-test-suite/MUS6/02/in.yaml new file mode 100644 index 0000000..168723f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/02/in.yaml @@ -0,0 +1,2 @@ +%YAML 1.1 +--- diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/02/test.event b/Tests/Fixtures/yaml-test-suite/MUS6/02/test.event new file mode 100644 index 0000000..e7a400d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/02/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/03/in.json b/Tests/Fixtures/yaml-test-suite/MUS6/03/in.json new file mode 100644 index 0000000..19765bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/03/in.json @@ -0,0 +1 @@ +null diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/03/in.yaml b/Tests/Fixtures/yaml-test-suite/MUS6/03/in.yaml new file mode 100644 index 0000000..c05cfdf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/03/in.yaml @@ -0,0 +1,2 @@ +%YAML 1.1 +--- diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/03/test.event b/Tests/Fixtures/yaml-test-suite/MUS6/03/test.event new file mode 100644 index 0000000..e7a400d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/03/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/04/in.json b/Tests/Fixtures/yaml-test-suite/MUS6/04/in.json new file mode 100644 index 0000000..19765bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/04/in.json @@ -0,0 +1 @@ +null diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/04/in.yaml b/Tests/Fixtures/yaml-test-suite/MUS6/04/in.yaml new file mode 100644 index 0000000..4fb8480 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/04/in.yaml @@ -0,0 +1,2 @@ +%YAML 1.1 # comment +--- diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/04/test.event b/Tests/Fixtures/yaml-test-suite/MUS6/04/test.event new file mode 100644 index 0000000..e7a400d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/04/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/05/in.json b/Tests/Fixtures/yaml-test-suite/MUS6/05/in.json new file mode 100644 index 0000000..19765bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/05/in.json @@ -0,0 +1 @@ +null diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/05/in.yaml b/Tests/Fixtures/yaml-test-suite/MUS6/05/in.yaml new file mode 100644 index 0000000..134cd49 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/05/in.yaml @@ -0,0 +1,2 @@ +%YAM 1.1 +--- diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/05/test.event b/Tests/Fixtures/yaml-test-suite/MUS6/05/test.event new file mode 100644 index 0000000..e7a400d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/05/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/06/in.json b/Tests/Fixtures/yaml-test-suite/MUS6/06/in.json new file mode 100644 index 0000000..19765bd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/06/in.json @@ -0,0 +1 @@ +null diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/06/in.yaml b/Tests/Fixtures/yaml-test-suite/MUS6/06/in.yaml new file mode 100644 index 0000000..2ae8800 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/06/in.yaml @@ -0,0 +1,2 @@ +%YAMLL 1.1 +--- diff --git a/Tests/Fixtures/yaml-test-suite/MUS6/06/test.event b/Tests/Fixtures/yaml-test-suite/MUS6/06/test.event new file mode 100644 index 0000000..e7a400d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MUS6/06/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MXS3/in.json b/Tests/Fixtures/yaml-test-suite/MXS3/in.json new file mode 100644 index 0000000..d107517 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MXS3/in.json @@ -0,0 +1,5 @@ +[ + { + "a": "b" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/MXS3/in.yaml b/Tests/Fixtures/yaml-test-suite/MXS3/in.yaml new file mode 100644 index 0000000..9d8ba51 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MXS3/in.yaml @@ -0,0 +1 @@ +- {a: b} diff --git a/Tests/Fixtures/yaml-test-suite/MXS3/test.event b/Tests/Fixtures/yaml-test-suite/MXS3/test.event new file mode 100644 index 0000000..9c0657f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MXS3/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ ++MAP {} +=VAL :a +=VAL :b +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MYW6/in.json b/Tests/Fixtures/yaml-test-suite/MYW6/in.json new file mode 100644 index 0000000..cb5537d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MYW6/in.json @@ -0,0 +1 @@ +"ab" diff --git a/Tests/Fixtures/yaml-test-suite/MYW6/in.yaml b/Tests/Fixtures/yaml-test-suite/MYW6/in.yaml new file mode 100644 index 0000000..1056edd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MYW6/in.yaml @@ -0,0 +1,5 @@ +|- + ab + + +... diff --git a/Tests/Fixtures/yaml-test-suite/MYW6/test.event b/Tests/Fixtures/yaml-test-suite/MYW6/test.event new file mode 100644 index 0000000..dbe3414 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MYW6/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL |ab +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/MZX3/in.json b/Tests/Fixtures/yaml-test-suite/MZX3/in.json new file mode 100644 index 0000000..2f701b1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MZX3/in.json @@ -0,0 +1,7 @@ +[ + "plain", + "double quoted", + "single quoted", + "block\n", + "plain again" +] diff --git a/Tests/Fixtures/yaml-test-suite/MZX3/in.yaml b/Tests/Fixtures/yaml-test-suite/MZX3/in.yaml new file mode 100644 index 0000000..81acc21 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MZX3/in.yaml @@ -0,0 +1,6 @@ +- plain +- "double quoted" +- 'single quoted' +- > + block +- plain again diff --git a/Tests/Fixtures/yaml-test-suite/MZX3/test.event b/Tests/Fixtures/yaml-test-suite/MZX3/test.event new file mode 100644 index 0000000..718e649 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/MZX3/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++SEQ +=VAL :plain +=VAL "double quoted +=VAL 'single quoted +=VAL >block\n +=VAL :plain again +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/N4JP/error b/Tests/Fixtures/yaml-test-suite/N4JP/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/N4JP/in.yaml b/Tests/Fixtures/yaml-test-suite/N4JP/in.yaml new file mode 100644 index 0000000..55c3038 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/N4JP/in.yaml @@ -0,0 +1,3 @@ +map: + key1: "quoted1" + key2: "bad indentation" diff --git a/Tests/Fixtures/yaml-test-suite/N4JP/test.event b/Tests/Fixtures/yaml-test-suite/N4JP/test.event new file mode 100644 index 0000000..ea73a26 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/N4JP/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :map ++MAP +=VAL :key1 +=VAL "quoted1 +-MAP diff --git a/Tests/Fixtures/yaml-test-suite/N782/error b/Tests/Fixtures/yaml-test-suite/N782/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/N782/in.yaml b/Tests/Fixtures/yaml-test-suite/N782/in.yaml new file mode 100644 index 0000000..ef7d8c4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/N782/in.yaml @@ -0,0 +1,4 @@ +[ +--- , +... +] diff --git a/Tests/Fixtures/yaml-test-suite/N782/test.event b/Tests/Fixtures/yaml-test-suite/N782/test.event new file mode 100644 index 0000000..b1282c7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/N782/test.event @@ -0,0 +1,3 @@ ++STR ++DOC ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/NAT4/in.json b/Tests/Fixtures/yaml-test-suite/NAT4/in.json new file mode 100644 index 0000000..f2cc7e8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NAT4/in.json @@ -0,0 +1,10 @@ +{ + "a": " ", + "b": " ", + "c": " ", + "d": " ", + "e": "\n", + "f": "\n", + "g": "\n\n", + "h": "\n\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/NAT4/in.yaml b/Tests/Fixtures/yaml-test-suite/NAT4/in.yaml new file mode 100644 index 0000000..10d58e2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NAT4/in.yaml @@ -0,0 +1,23 @@ +--- +a: ' + ' +b: ' + ' +c: " + " +d: " + " +e: ' + + ' +f: " + + " +g: ' + + + ' +h: " + + + " diff --git a/Tests/Fixtures/yaml-test-suite/NAT4/test.event b/Tests/Fixtures/yaml-test-suite/NAT4/test.event new file mode 100644 index 0000000..0b01bbf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NAT4/test.event @@ -0,0 +1,22 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL ' +=VAL :b +=VAL ' +=VAL :c +=VAL " +=VAL :d +=VAL " +=VAL :e +=VAL '\n +=VAL :f +=VAL "\n +=VAL :g +=VAL '\n\n +=VAL :h +=VAL "\n\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/NB6Z/in.json b/Tests/Fixtures/yaml-test-suite/NB6Z/in.json new file mode 100644 index 0000000..99213fe --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NB6Z/in.json @@ -0,0 +1,3 @@ +{ + "key": "value with\ntabs" +} diff --git a/Tests/Fixtures/yaml-test-suite/NB6Z/in.yaml b/Tests/Fixtures/yaml-test-suite/NB6Z/in.yaml new file mode 100644 index 0000000..b7cf4b1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NB6Z/in.yaml @@ -0,0 +1,5 @@ +key: + value + with + + tabs diff --git a/Tests/Fixtures/yaml-test-suite/NB6Z/test.event b/Tests/Fixtures/yaml-test-suite/NB6Z/test.event new file mode 100644 index 0000000..83b64c3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NB6Z/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :key +=VAL :value with\ntabs +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/NHX8/in.yaml b/Tests/Fixtures/yaml-test-suite/NHX8/in.yaml new file mode 100644 index 0000000..2c0664b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NHX8/in.yaml @@ -0,0 +1,3 @@ +: + + diff --git a/Tests/Fixtures/yaml-test-suite/NHX8/test.event b/Tests/Fixtures/yaml-test-suite/NHX8/test.event new file mode 100644 index 0000000..5e2623a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NHX8/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL : +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/NJ66/in.json b/Tests/Fixtures/yaml-test-suite/NJ66/in.json new file mode 100644 index 0000000..d214d88 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NJ66/in.json @@ -0,0 +1,8 @@ +[ + { + "single line": "value" + }, + { + "multi line": "value" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/NJ66/in.yaml b/Tests/Fixtures/yaml-test-suite/NJ66/in.yaml new file mode 100644 index 0000000..6ded532 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NJ66/in.yaml @@ -0,0 +1,4 @@ +--- +- { single line: value} +- { multi + line: value} diff --git a/Tests/Fixtures/yaml-test-suite/NJ66/test.event b/Tests/Fixtures/yaml-test-suite/NJ66/test.event new file mode 100644 index 0000000..8845a03 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NJ66/test.event @@ -0,0 +1,14 @@ ++STR ++DOC --- ++SEQ ++MAP {} +=VAL :single line +=VAL :value +-MAP ++MAP {} +=VAL :multi line +=VAL :value +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/NKF9/in.yaml b/Tests/Fixtures/yaml-test-suite/NKF9/in.yaml new file mode 100644 index 0000000..30c07c2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NKF9/in.yaml @@ -0,0 +1,13 @@ +--- +key: value +: empty key +--- +{ + key: value, : empty key +} +--- +# empty key and value +: +--- +# empty key and value +{ : } diff --git a/Tests/Fixtures/yaml-test-suite/NKF9/test.event b/Tests/Fixtures/yaml-test-suite/NKF9/test.event new file mode 100644 index 0000000..d63dcd5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NKF9/test.event @@ -0,0 +1,30 @@ ++STR ++DOC --- ++MAP +=VAL :key +=VAL :value +=VAL : +=VAL :empty key +-MAP +-DOC ++DOC --- ++MAP {} +=VAL :key +=VAL :value +=VAL : +=VAL :empty key +-MAP +-DOC ++DOC --- ++MAP +=VAL : +=VAL : +-MAP +-DOC ++DOC --- ++MAP {} +=VAL : +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/NP9H/in.json b/Tests/Fixtures/yaml-test-suite/NP9H/in.json new file mode 100644 index 0000000..6ab3718 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NP9H/in.json @@ -0,0 +1 @@ +"folded to a space,\nto a line feed, or \t \tnon-content" diff --git a/Tests/Fixtures/yaml-test-suite/NP9H/in.yaml b/Tests/Fixtures/yaml-test-suite/NP9H/in.yaml new file mode 100644 index 0000000..eda4b49 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NP9H/in.yaml @@ -0,0 +1,5 @@ +"folded +to a space, + +to a line feed, or \ + \ non-content" diff --git a/Tests/Fixtures/yaml-test-suite/NP9H/test.event b/Tests/Fixtures/yaml-test-suite/NP9H/test.event new file mode 100644 index 0000000..7dc23fc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/NP9H/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL "folded to a space,\nto a line feed, or \t \tnon-content +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/P2AD/in.json b/Tests/Fixtures/yaml-test-suite/P2AD/in.json new file mode 100644 index 0000000..4e476d6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P2AD/in.json @@ -0,0 +1,6 @@ +[ + "literal\n", + " folded\n", + "keep\n\n", + " strip" +] diff --git a/Tests/Fixtures/yaml-test-suite/P2AD/in.yaml b/Tests/Fixtures/yaml-test-suite/P2AD/in.yaml new file mode 100644 index 0000000..1dbadca --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P2AD/in.yaml @@ -0,0 +1,9 @@ +- | # Empty header↓ + literal +- >1 # Indentation indicator↓ + folded +- |+ # Chomping indicator↓ + keep + +- >1- # Both indicators↓ + strip diff --git a/Tests/Fixtures/yaml-test-suite/P2AD/test.event b/Tests/Fixtures/yaml-test-suite/P2AD/test.event new file mode 100644 index 0000000..cd1a323 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P2AD/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ +=VAL |literal\n +=VAL > folded\n +=VAL |keep\n\n +=VAL > strip +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/P2EQ/error b/Tests/Fixtures/yaml-test-suite/P2EQ/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/P2EQ/in.yaml b/Tests/Fixtures/yaml-test-suite/P2EQ/in.yaml new file mode 100644 index 0000000..a12dd55 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P2EQ/in.yaml @@ -0,0 +1,2 @@ +--- +- { y: z }- invalid diff --git a/Tests/Fixtures/yaml-test-suite/P2EQ/test.event b/Tests/Fixtures/yaml-test-suite/P2EQ/test.event new file mode 100644 index 0000000..759eaf4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P2EQ/test.event @@ -0,0 +1,7 @@ ++STR ++DOC --- ++SEQ ++MAP {} +=VAL :y +=VAL :z +-MAP diff --git a/Tests/Fixtures/yaml-test-suite/P76L/in.json b/Tests/Fixtures/yaml-test-suite/P76L/in.json new file mode 100644 index 0000000..8394b3d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P76L/in.json @@ -0,0 +1 @@ +"1 - 3" diff --git a/Tests/Fixtures/yaml-test-suite/P76L/in.yaml b/Tests/Fixtures/yaml-test-suite/P76L/in.yaml new file mode 100644 index 0000000..7b9d9b1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P76L/in.yaml @@ -0,0 +1,3 @@ +%TAG !! tag:example.com,2000:app/ +--- +!!int 1 - 3 # Interval, not integer diff --git a/Tests/Fixtures/yaml-test-suite/P76L/test.event b/Tests/Fixtures/yaml-test-suite/P76L/test.event new file mode 100644 index 0000000..c008088 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P76L/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :1 - 3 +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/P94K/in.json b/Tests/Fixtures/yaml-test-suite/P94K/in.json new file mode 100644 index 0000000..7a9e864 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P94K/in.json @@ -0,0 +1,3 @@ +{ + "key": "value" +} diff --git a/Tests/Fixtures/yaml-test-suite/P94K/in.yaml b/Tests/Fixtures/yaml-test-suite/P94K/in.yaml new file mode 100644 index 0000000..6776e8a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P94K/in.yaml @@ -0,0 +1,5 @@ +key: # Comment + # lines + value + + diff --git a/Tests/Fixtures/yaml-test-suite/P94K/test.event b/Tests/Fixtures/yaml-test-suite/P94K/test.event new file mode 100644 index 0000000..4010c9a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/P94K/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :key +=VAL :value +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/PBJ2/in.json b/Tests/Fixtures/yaml-test-suite/PBJ2/in.json new file mode 100644 index 0000000..7d19aaf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PBJ2/in.json @@ -0,0 +1,12 @@ +{ + "american": [ + "Boston Red Sox", + "Detroit Tigers", + "New York Yankees" + ], + "national": [ + "New York Mets", + "Chicago Cubs", + "Atlanta Braves" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/PBJ2/in.yaml b/Tests/Fixtures/yaml-test-suite/PBJ2/in.yaml new file mode 100644 index 0000000..656d628 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PBJ2/in.yaml @@ -0,0 +1,8 @@ +american: + - Boston Red Sox + - Detroit Tigers + - New York Yankees +national: + - New York Mets + - Chicago Cubs + - Atlanta Braves diff --git a/Tests/Fixtures/yaml-test-suite/PBJ2/test.event b/Tests/Fixtures/yaml-test-suite/PBJ2/test.event new file mode 100644 index 0000000..063b205 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PBJ2/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++MAP +=VAL :american ++SEQ +=VAL :Boston Red Sox +=VAL :Detroit Tigers +=VAL :New York Yankees +-SEQ +=VAL :national ++SEQ +=VAL :New York Mets +=VAL :Chicago Cubs +=VAL :Atlanta Braves +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/PRH3/in.json b/Tests/Fixtures/yaml-test-suite/PRH3/in.json new file mode 100644 index 0000000..2dfab84 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PRH3/in.json @@ -0,0 +1 @@ +" 1st non-empty\n2nd non-empty 3rd non-empty " diff --git a/Tests/Fixtures/yaml-test-suite/PRH3/in.yaml b/Tests/Fixtures/yaml-test-suite/PRH3/in.yaml new file mode 100644 index 0000000..6dd946e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PRH3/in.yaml @@ -0,0 +1,4 @@ +' 1st non-empty + + 2nd non-empty + 3rd non-empty ' diff --git a/Tests/Fixtures/yaml-test-suite/PRH3/test.event b/Tests/Fixtures/yaml-test-suite/PRH3/test.event new file mode 100644 index 0000000..bda01d7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PRH3/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL ' 1st non-empty\n2nd non-empty 3rd non-empty +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/PUW8/in.json b/Tests/Fixtures/yaml-test-suite/PUW8/in.json new file mode 100644 index 0000000..88bf67f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PUW8/in.json @@ -0,0 +1,4 @@ +{ + "a": "b" +} +null diff --git a/Tests/Fixtures/yaml-test-suite/PUW8/in.yaml b/Tests/Fixtures/yaml-test-suite/PUW8/in.yaml new file mode 100644 index 0000000..6e88f36 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PUW8/in.yaml @@ -0,0 +1,3 @@ +--- +a: b +--- diff --git a/Tests/Fixtures/yaml-test-suite/PUW8/test.event b/Tests/Fixtures/yaml-test-suite/PUW8/test.event new file mode 100644 index 0000000..bde47e1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PUW8/test.event @@ -0,0 +1,11 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL :b +-MAP +-DOC ++DOC --- +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/PW8X/in.yaml b/Tests/Fixtures/yaml-test-suite/PW8X/in.yaml new file mode 100644 index 0000000..23cbbb1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PW8X/in.yaml @@ -0,0 +1,12 @@ +- &a +- a +- + &a : a + b: &b +- + &c : &a +- + ? &d +- + ? &e + : &a diff --git a/Tests/Fixtures/yaml-test-suite/PW8X/test.event b/Tests/Fixtures/yaml-test-suite/PW8X/test.event new file mode 100644 index 0000000..dabd798 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/PW8X/test.event @@ -0,0 +1,26 @@ ++STR ++DOC ++SEQ +=VAL &a : +=VAL :a ++MAP +=VAL &a : +=VAL :a +=VAL :b +=VAL &b : +-MAP ++MAP +=VAL &c : +=VAL &a : +-MAP ++MAP +=VAL &d : +=VAL : +-MAP ++MAP +=VAL &e : +=VAL &a : +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Q4CL/error b/Tests/Fixtures/yaml-test-suite/Q4CL/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Q4CL/in.yaml b/Tests/Fixtures/yaml-test-suite/Q4CL/in.yaml new file mode 100644 index 0000000..425342a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q4CL/in.yaml @@ -0,0 +1,3 @@ +key1: "quoted1" +key2: "quoted2" trailing content +key3: "quoted3" diff --git a/Tests/Fixtures/yaml-test-suite/Q4CL/test.event b/Tests/Fixtures/yaml-test-suite/Q4CL/test.event new file mode 100644 index 0000000..128a5c5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q4CL/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++MAP +=VAL :key1 +=VAL "quoted1 +=VAL :key2 +=VAL "quoted2 diff --git a/Tests/Fixtures/yaml-test-suite/Q5MG/in.json b/Tests/Fixtures/yaml-test-suite/Q5MG/in.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q5MG/in.json @@ -0,0 +1 @@ +{} diff --git a/Tests/Fixtures/yaml-test-suite/Q5MG/in.yaml b/Tests/Fixtures/yaml-test-suite/Q5MG/in.yaml new file mode 100644 index 0000000..db07de0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q5MG/in.yaml @@ -0,0 +1 @@ + {} diff --git a/Tests/Fixtures/yaml-test-suite/Q5MG/test.event b/Tests/Fixtures/yaml-test-suite/Q5MG/test.event new file mode 100644 index 0000000..a1aa51f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q5MG/test.event @@ -0,0 +1,6 @@ ++STR ++DOC ++MAP {} +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Q88A/in.json b/Tests/Fixtures/yaml-test-suite/Q88A/in.json new file mode 100644 index 0000000..d88afe7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q88A/in.json @@ -0,0 +1,12 @@ +[ + [ + "a", + "b" + ], + { + "a": "b" + }, + "a", + "b", + "c" +] diff --git a/Tests/Fixtures/yaml-test-suite/Q88A/in.yaml b/Tests/Fixtures/yaml-test-suite/Q88A/in.yaml new file mode 100644 index 0000000..f709dc8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q88A/in.yaml @@ -0,0 +1,5 @@ +- [ a, b ] +- { a: b } +- "a" +- 'b' +- c diff --git a/Tests/Fixtures/yaml-test-suite/Q88A/test.event b/Tests/Fixtures/yaml-test-suite/Q88A/test.event new file mode 100644 index 0000000..abd1118 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q88A/test.event @@ -0,0 +1,17 @@ ++STR ++DOC ++SEQ ++SEQ [] +=VAL :a +=VAL :b +-SEQ ++MAP {} +=VAL :a +=VAL :b +-MAP +=VAL "a +=VAL 'b +=VAL :c +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Q8AD/in.json b/Tests/Fixtures/yaml-test-suite/Q8AD/in.json new file mode 100644 index 0000000..6ab3718 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q8AD/in.json @@ -0,0 +1 @@ +"folded to a space,\nto a line feed, or \t \tnon-content" diff --git a/Tests/Fixtures/yaml-test-suite/Q8AD/in.yaml b/Tests/Fixtures/yaml-test-suite/Q8AD/in.yaml new file mode 100644 index 0000000..bf14c53 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q8AD/in.yaml @@ -0,0 +1,6 @@ +--- +"folded +to a space, + +to a line feed, or \ + \ non-content" diff --git a/Tests/Fixtures/yaml-test-suite/Q8AD/test.event b/Tests/Fixtures/yaml-test-suite/Q8AD/test.event new file mode 100644 index 0000000..31a447e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q8AD/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL "folded to a space,\nto a line feed, or \t \tnon-content +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Q9WF/in.yaml b/Tests/Fixtures/yaml-test-suite/Q9WF/in.yaml new file mode 100644 index 0000000..e1e1113 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q9WF/in.yaml @@ -0,0 +1,6 @@ +{ first: Sammy, last: Sosa }: +# Statistics: + hr: # Home runs + 65 + avg: # Average + 0.278 diff --git a/Tests/Fixtures/yaml-test-suite/Q9WF/test.event b/Tests/Fixtures/yaml-test-suite/Q9WF/test.event new file mode 100644 index 0000000..2d4c714 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Q9WF/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++MAP ++MAP {} +=VAL :first +=VAL :Sammy +=VAL :last +=VAL :Sosa +-MAP ++MAP +=VAL :hr +=VAL :65 +=VAL :avg +=VAL :0.278 +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/QB6E/error b/Tests/Fixtures/yaml-test-suite/QB6E/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/QB6E/in.yaml b/Tests/Fixtures/yaml-test-suite/QB6E/in.yaml new file mode 100644 index 0000000..cdbb0da --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QB6E/in.yaml @@ -0,0 +1,4 @@ +--- +quoted: "a +b +c" diff --git a/Tests/Fixtures/yaml-test-suite/QB6E/test.event b/Tests/Fixtures/yaml-test-suite/QB6E/test.event new file mode 100644 index 0000000..7e886f0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QB6E/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :quoted diff --git a/Tests/Fixtures/yaml-test-suite/QF4Y/in.json b/Tests/Fixtures/yaml-test-suite/QF4Y/in.json new file mode 100644 index 0000000..15925a4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QF4Y/in.json @@ -0,0 +1,5 @@ +[ + { + "foo": "bar" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/QF4Y/in.yaml b/Tests/Fixtures/yaml-test-suite/QF4Y/in.yaml new file mode 100644 index 0000000..77f3eb3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QF4Y/in.yaml @@ -0,0 +1,3 @@ +[ +foo: bar +] diff --git a/Tests/Fixtures/yaml-test-suite/QF4Y/test.event b/Tests/Fixtures/yaml-test-suite/QF4Y/test.event new file mode 100644 index 0000000..f44b36d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QF4Y/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ [] ++MAP {} +=VAL :foo +=VAL :bar +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/QLJ7/error b/Tests/Fixtures/yaml-test-suite/QLJ7/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/QLJ7/in.yaml b/Tests/Fixtures/yaml-test-suite/QLJ7/in.yaml new file mode 100644 index 0000000..2a1ec44 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QLJ7/in.yaml @@ -0,0 +1,7 @@ +%TAG !prefix! tag:example.com,2011: +--- !prefix!A +a: b +--- !prefix!B +c: d +--- !prefix!C +e: f diff --git a/Tests/Fixtures/yaml-test-suite/QLJ7/test.event b/Tests/Fixtures/yaml-test-suite/QLJ7/test.event new file mode 100644 index 0000000..0215625 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QLJ7/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL :b +-MAP +-DOC ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/QT73/in.json b/Tests/Fixtures/yaml-test-suite/QT73/in.json new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/QT73/in.yaml b/Tests/Fixtures/yaml-test-suite/QT73/in.yaml new file mode 100644 index 0000000..84cd22e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QT73/in.yaml @@ -0,0 +1,2 @@ +# comment +... diff --git a/Tests/Fixtures/yaml-test-suite/QT73/test.event b/Tests/Fixtures/yaml-test-suite/QT73/test.event new file mode 100644 index 0000000..a8c0574 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/QT73/test.event @@ -0,0 +1,2 @@ ++STR +-STR diff --git a/Tests/Fixtures/yaml-test-suite/R4YG/in.json b/Tests/Fixtures/yaml-test-suite/R4YG/in.json new file mode 100644 index 0000000..f84df1f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/R4YG/in.json @@ -0,0 +1,6 @@ +[ + "detected\n", + "\n\n# detected\n", + " explicit\n", + "\t\ndetected\n" +] diff --git a/Tests/Fixtures/yaml-test-suite/R4YG/in.yaml b/Tests/Fixtures/yaml-test-suite/R4YG/in.yaml new file mode 100644 index 0000000..39bee04 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/R4YG/in.yaml @@ -0,0 +1,11 @@ +- | + detected +- > + + + # detected +- |1 + explicit +- > + + detected diff --git a/Tests/Fixtures/yaml-test-suite/R4YG/test.event b/Tests/Fixtures/yaml-test-suite/R4YG/test.event new file mode 100644 index 0000000..9364e01 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/R4YG/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ +=VAL |detected\n +=VAL >\n\n# detected\n +=VAL | explicit\n +=VAL >\t\ndetected\n +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/R52L/in.json b/Tests/Fixtures/yaml-test-suite/R52L/in.json new file mode 100644 index 0000000..e028548 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/R52L/in.json @@ -0,0 +1,10 @@ +{ + "top1": [ + "item1", + { + "key2": "value2" + }, + "item3" + ], + "top2": "value2" +} diff --git a/Tests/Fixtures/yaml-test-suite/R52L/in.yaml b/Tests/Fixtures/yaml-test-suite/R52L/in.yaml new file mode 100644 index 0000000..1add8f8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/R52L/in.yaml @@ -0,0 +1,2 @@ +--- +{ top1: [item1, {key2: value2}, item3], top2: value2 } diff --git a/Tests/Fixtures/yaml-test-suite/R52L/test.event b/Tests/Fixtures/yaml-test-suite/R52L/test.event new file mode 100644 index 0000000..eb8054a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/R52L/test.event @@ -0,0 +1,17 @@ ++STR ++DOC --- ++MAP {} +=VAL :top1 ++SEQ [] +=VAL :item1 ++MAP {} +=VAL :key2 +=VAL :value2 +-MAP +=VAL :item3 +-SEQ +=VAL :top2 +=VAL :value2 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/RHX7/error b/Tests/Fixtures/yaml-test-suite/RHX7/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/RHX7/in.yaml b/Tests/Fixtures/yaml-test-suite/RHX7/in.yaml new file mode 100644 index 0000000..8ff8337 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RHX7/in.yaml @@ -0,0 +1,4 @@ +--- +key: value +%YAML 1.2 +--- diff --git a/Tests/Fixtures/yaml-test-suite/RHX7/test.event b/Tests/Fixtures/yaml-test-suite/RHX7/test.event new file mode 100644 index 0000000..335f6e4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RHX7/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- ++MAP +=VAL :key +=VAL :value diff --git a/Tests/Fixtures/yaml-test-suite/RLU9/in.json b/Tests/Fixtures/yaml-test-suite/RLU9/in.json new file mode 100644 index 0000000..ab6d5e3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RLU9/in.json @@ -0,0 +1,8 @@ +{ + "foo": [ + 42 + ], + "bar": [ + 44 + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/RLU9/in.yaml b/Tests/Fixtures/yaml-test-suite/RLU9/in.yaml new file mode 100644 index 0000000..5896eef --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RLU9/in.yaml @@ -0,0 +1,4 @@ +foo: +- 42 +bar: + - 44 diff --git a/Tests/Fixtures/yaml-test-suite/RLU9/test.event b/Tests/Fixtures/yaml-test-suite/RLU9/test.event new file mode 100644 index 0000000..a08b894 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RLU9/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :foo ++SEQ +=VAL :42 +-SEQ +=VAL :bar ++SEQ +=VAL :44 +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/RR7F/in.json b/Tests/Fixtures/yaml-test-suite/RR7F/in.json new file mode 100644 index 0000000..ee9c8be --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RR7F/in.json @@ -0,0 +1,4 @@ +{ + "d": 23, + "a": 4.2 +} diff --git a/Tests/Fixtures/yaml-test-suite/RR7F/in.yaml b/Tests/Fixtures/yaml-test-suite/RR7F/in.yaml new file mode 100644 index 0000000..34ccc87 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RR7F/in.yaml @@ -0,0 +1,3 @@ +a: 4.2 +? d +: 23 diff --git a/Tests/Fixtures/yaml-test-suite/RR7F/test.event b/Tests/Fixtures/yaml-test-suite/RR7F/test.event new file mode 100644 index 0000000..b547f0a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RR7F/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL :4.2 +=VAL :d +=VAL :23 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/RTP8/in.json b/Tests/Fixtures/yaml-test-suite/RTP8/in.json new file mode 100644 index 0000000..f1131de --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RTP8/in.json @@ -0,0 +1 @@ +"Document" diff --git a/Tests/Fixtures/yaml-test-suite/RTP8/in.yaml b/Tests/Fixtures/yaml-test-suite/RTP8/in.yaml new file mode 100644 index 0000000..886e574 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RTP8/in.yaml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +Document +... # Suffix diff --git a/Tests/Fixtures/yaml-test-suite/RTP8/test.event b/Tests/Fixtures/yaml-test-suite/RTP8/test.event new file mode 100644 index 0000000..914e23e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RTP8/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :Document +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/RXY3/error b/Tests/Fixtures/yaml-test-suite/RXY3/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/RXY3/in.yaml b/Tests/Fixtures/yaml-test-suite/RXY3/in.yaml new file mode 100644 index 0000000..5c9530e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RXY3/in.yaml @@ -0,0 +1,4 @@ +--- +' +... +' diff --git a/Tests/Fixtures/yaml-test-suite/RXY3/test.event b/Tests/Fixtures/yaml-test-suite/RXY3/test.event new file mode 100644 index 0000000..19c9481 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RXY3/test.event @@ -0,0 +1,2 @@ ++STR ++DOC --- diff --git a/Tests/Fixtures/yaml-test-suite/RZP5/in.yaml b/Tests/Fixtures/yaml-test-suite/RZP5/in.yaml new file mode 100644 index 0000000..a18e345 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RZP5/in.yaml @@ -0,0 +1,15 @@ +a: "double + quotes" # lala +b: plain + value # lala +c : #lala + d +? # lala + - seq1 +: # lala + - #lala + seq2 +e: &node # lala + - x: y +block: > # lala + abcde diff --git a/Tests/Fixtures/yaml-test-suite/RZP5/test.event b/Tests/Fixtures/yaml-test-suite/RZP5/test.event new file mode 100644 index 0000000..fc2031d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RZP5/test.event @@ -0,0 +1,27 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL "double quotes +=VAL :b +=VAL :plain value +=VAL :c +=VAL :d ++SEQ +=VAL :seq1 +-SEQ ++SEQ +=VAL :seq2 +-SEQ +=VAL :e ++SEQ &node ++MAP +=VAL :x +=VAL :y +-MAP +-SEQ +=VAL :block +=VAL >abcde\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/RZT7/in.json b/Tests/Fixtures/yaml-test-suite/RZT7/in.json new file mode 100644 index 0000000..2331472 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RZT7/in.json @@ -0,0 +1,27 @@ +{ + "Time": "2001-11-23 15:01:42 -5", + "User": "ed", + "Warning": "This is an error message for the log file" +} +{ + "Time": "2001-11-23 15:02:31 -5", + "User": "ed", + "Warning": "A slightly different error message." +} +{ + "Date": "2001-11-23 15:03:17 -5", + "User": "ed", + "Fatal": "Unknown variable \"bar\"", + "Stack": [ + { + "file": "TopClass.py", + "line": 23, + "code": "x = MoreObject(\"345\\n\")\n" + }, + { + "file": "MoreClass.py", + "line": 58, + "code": "foo = bar" + } + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/RZT7/in.yaml b/Tests/Fixtures/yaml-test-suite/RZT7/in.yaml new file mode 100644 index 0000000..a5c8dc8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RZT7/in.yaml @@ -0,0 +1,26 @@ +--- +Time: 2001-11-23 15:01:42 -5 +User: ed +Warning: + This is an error message + for the log file +--- +Time: 2001-11-23 15:02:31 -5 +User: ed +Warning: + A slightly different error + message. +--- +Date: 2001-11-23 15:03:17 -5 +User: ed +Fatal: + Unknown variable "bar" +Stack: + - file: TopClass.py + line: 23 + code: | + x = MoreObject("345\n") + - file: MoreClass.py + line: 58 + code: |- + foo = bar diff --git a/Tests/Fixtures/yaml-test-suite/RZT7/test.event b/Tests/Fixtures/yaml-test-suite/RZT7/test.event new file mode 100644 index 0000000..44707fb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/RZT7/test.event @@ -0,0 +1,51 @@ ++STR ++DOC --- ++MAP +=VAL :Time +=VAL :2001-11-23 15:01:42 -5 +=VAL :User +=VAL :ed +=VAL :Warning +=VAL :This is an error message for the log file +-MAP +-DOC ++DOC --- ++MAP +=VAL :Time +=VAL :2001-11-23 15:02:31 -5 +=VAL :User +=VAL :ed +=VAL :Warning +=VAL :A slightly different error message. +-MAP +-DOC ++DOC --- ++MAP +=VAL :Date +=VAL :2001-11-23 15:03:17 -5 +=VAL :User +=VAL :ed +=VAL :Fatal +=VAL :Unknown variable "bar" +=VAL :Stack ++SEQ ++MAP +=VAL :file +=VAL :TopClass.py +=VAL :line +=VAL :23 +=VAL :code +=VAL |x = MoreObject("345\\n")\n +-MAP ++MAP +=VAL :file +=VAL :MoreClass.py +=VAL :line +=VAL :58 +=VAL :code +=VAL |foo = bar +-MAP +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/S3PD/in.yaml b/Tests/Fixtures/yaml-test-suite/S3PD/in.yaml new file mode 100644 index 0000000..c819512 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S3PD/in.yaml @@ -0,0 +1,4 @@ +plain key: in-line value +: # Both empty +"quoted key": +- entry diff --git a/Tests/Fixtures/yaml-test-suite/S3PD/test.event b/Tests/Fixtures/yaml-test-suite/S3PD/test.event new file mode 100644 index 0000000..c2e58b5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S3PD/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP +=VAL :plain key +=VAL :in-line value +=VAL : +=VAL : +=VAL "quoted key ++SEQ +=VAL :entry +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/S4GJ/error b/Tests/Fixtures/yaml-test-suite/S4GJ/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/S4GJ/in.yaml b/Tests/Fixtures/yaml-test-suite/S4GJ/in.yaml new file mode 100644 index 0000000..a555507 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4GJ/in.yaml @@ -0,0 +1,3 @@ +--- +folded: > first line + second line diff --git a/Tests/Fixtures/yaml-test-suite/S4GJ/test.event b/Tests/Fixtures/yaml-test-suite/S4GJ/test.event new file mode 100644 index 0000000..f5369ce --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4GJ/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :folded diff --git a/Tests/Fixtures/yaml-test-suite/S4JQ/in.json b/Tests/Fixtures/yaml-test-suite/S4JQ/in.json new file mode 100644 index 0000000..72d72b2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4JQ/in.json @@ -0,0 +1,5 @@ +[ + "12", + 12, + "12" +] diff --git a/Tests/Fixtures/yaml-test-suite/S4JQ/in.yaml b/Tests/Fixtures/yaml-test-suite/S4JQ/in.yaml new file mode 100644 index 0000000..98aa565 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4JQ/in.yaml @@ -0,0 +1,4 @@ +# Assuming conventional resolution: +- "12" +- 12 +- ! 12 diff --git a/Tests/Fixtures/yaml-test-suite/S4JQ/test.event b/Tests/Fixtures/yaml-test-suite/S4JQ/test.event new file mode 100644 index 0000000..3f9e502 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4JQ/test.event @@ -0,0 +1,9 @@ ++STR ++DOC ++SEQ +=VAL "12 +=VAL :12 +=VAL :12 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/S4T7/in.json b/Tests/Fixtures/yaml-test-suite/S4T7/in.json new file mode 100644 index 0000000..049aa9e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4T7/in.json @@ -0,0 +1,3 @@ +{ + "aaa": "bbb" +} diff --git a/Tests/Fixtures/yaml-test-suite/S4T7/in.yaml b/Tests/Fixtures/yaml-test-suite/S4T7/in.yaml new file mode 100644 index 0000000..4fc70de --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4T7/in.yaml @@ -0,0 +1,2 @@ +aaa: bbb +... diff --git a/Tests/Fixtures/yaml-test-suite/S4T7/test.event b/Tests/Fixtures/yaml-test-suite/S4T7/test.event new file mode 100644 index 0000000..1e55d45 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S4T7/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :aaa +=VAL :bbb +-MAP +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/S7BG/in.json b/Tests/Fixtures/yaml-test-suite/S7BG/in.json new file mode 100644 index 0000000..eadfbdc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S7BG/in.json @@ -0,0 +1,3 @@ +[ + ":," +] diff --git a/Tests/Fixtures/yaml-test-suite/S7BG/in.yaml b/Tests/Fixtures/yaml-test-suite/S7BG/in.yaml new file mode 100644 index 0000000..db7f229 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S7BG/in.yaml @@ -0,0 +1,2 @@ +--- +- :, diff --git a/Tests/Fixtures/yaml-test-suite/S7BG/test.event b/Tests/Fixtures/yaml-test-suite/S7BG/test.event new file mode 100644 index 0000000..4c9bafd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S7BG/test.event @@ -0,0 +1,7 @@ ++STR ++DOC --- ++SEQ +=VAL ::, +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/S98Z/error b/Tests/Fixtures/yaml-test-suite/S98Z/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/S98Z/in.yaml b/Tests/Fixtures/yaml-test-suite/S98Z/in.yaml new file mode 100644 index 0000000..3574e02 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S98Z/in.yaml @@ -0,0 +1,5 @@ +empty block scalar: > + + + + # comment diff --git a/Tests/Fixtures/yaml-test-suite/S98Z/test.event b/Tests/Fixtures/yaml-test-suite/S98Z/test.event new file mode 100644 index 0000000..1fbf5d0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S98Z/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :empty block scalar diff --git a/Tests/Fixtures/yaml-test-suite/S9E8/in.json b/Tests/Fixtures/yaml-test-suite/S9E8/in.json new file mode 100644 index 0000000..cecac0c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S9E8/in.json @@ -0,0 +1,10 @@ +{ + "sequence": [ + "one", + "two" + ], + "mapping": { + "sky": "blue", + "sea": "green" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/S9E8/in.yaml b/Tests/Fixtures/yaml-test-suite/S9E8/in.yaml new file mode 100644 index 0000000..608ea19 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S9E8/in.yaml @@ -0,0 +1,7 @@ +sequence: +- one +- two +mapping: + ? sky + : blue + sea : green diff --git a/Tests/Fixtures/yaml-test-suite/S9E8/test.event b/Tests/Fixtures/yaml-test-suite/S9E8/test.event new file mode 100644 index 0000000..d3c22b9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/S9E8/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++MAP +=VAL :sequence ++SEQ +=VAL :one +=VAL :two +-SEQ +=VAL :mapping ++MAP +=VAL :sky +=VAL :blue +=VAL :sea +=VAL :green +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/SBG9/in.yaml b/Tests/Fixtures/yaml-test-suite/SBG9/in.yaml new file mode 100644 index 0000000..e6e30e2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SBG9/in.yaml @@ -0,0 +1 @@ +{a: [b, c], [d, e]: f} diff --git a/Tests/Fixtures/yaml-test-suite/SBG9/test.event b/Tests/Fixtures/yaml-test-suite/SBG9/test.event new file mode 100644 index 0000000..dc986ab --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SBG9/test.event @@ -0,0 +1,16 @@ ++STR ++DOC ++MAP {} +=VAL :a ++SEQ [] +=VAL :b +=VAL :c +-SEQ ++SEQ [] +=VAL :d +=VAL :e +-SEQ +=VAL :f +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/SF5V/error b/Tests/Fixtures/yaml-test-suite/SF5V/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/SF5V/in.yaml b/Tests/Fixtures/yaml-test-suite/SF5V/in.yaml new file mode 100644 index 0000000..cb5488f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SF5V/in.yaml @@ -0,0 +1,3 @@ +%YAML 1.2 +%YAML 1.2 +--- diff --git a/Tests/Fixtures/yaml-test-suite/SF5V/test.event b/Tests/Fixtures/yaml-test-suite/SF5V/test.event new file mode 100644 index 0000000..e72d602 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SF5V/test.event @@ -0,0 +1 @@ ++STR diff --git a/Tests/Fixtures/yaml-test-suite/SKE5/in.json b/Tests/Fixtures/yaml-test-suite/SKE5/in.json new file mode 100644 index 0000000..8c9471e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SKE5/in.json @@ -0,0 +1,6 @@ +{ + "seq": [ + "a", + "b" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/SKE5/in.yaml b/Tests/Fixtures/yaml-test-suite/SKE5/in.yaml new file mode 100644 index 0000000..6a8937a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SKE5/in.yaml @@ -0,0 +1,5 @@ +--- +seq: + &anchor +- a +- b diff --git a/Tests/Fixtures/yaml-test-suite/SKE5/test.event b/Tests/Fixtures/yaml-test-suite/SKE5/test.event new file mode 100644 index 0000000..21cb837 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SKE5/test.event @@ -0,0 +1,11 @@ ++STR ++DOC --- ++MAP +=VAL :seq ++SEQ &anchor +=VAL :a +=VAL :b +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/SM9W/00/in.json b/Tests/Fixtures/yaml-test-suite/SM9W/00/in.json new file mode 100644 index 0000000..62864b3 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SM9W/00/in.json @@ -0,0 +1 @@ +[null] diff --git a/Tests/Fixtures/yaml-test-suite/SM9W/00/in.yaml b/Tests/Fixtures/yaml-test-suite/SM9W/00/in.yaml new file mode 100644 index 0000000..3cf20d5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SM9W/00/in.yaml @@ -0,0 +1 @@ +- \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/SM9W/00/test.event b/Tests/Fixtures/yaml-test-suite/SM9W/00/test.event new file mode 100644 index 0000000..02b6399 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SM9W/00/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ +=VAL : +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/SM9W/01/in.yaml b/Tests/Fixtures/yaml-test-suite/SM9W/01/in.yaml new file mode 100644 index 0000000..22ded55 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SM9W/01/in.yaml @@ -0,0 +1 @@ +: \ No newline at end of file diff --git a/Tests/Fixtures/yaml-test-suite/SM9W/01/test.event b/Tests/Fixtures/yaml-test-suite/SM9W/01/test.event new file mode 100644 index 0000000..5e2623a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SM9W/01/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL : +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/SR86/error b/Tests/Fixtures/yaml-test-suite/SR86/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/SR86/in.yaml b/Tests/Fixtures/yaml-test-suite/SR86/in.yaml new file mode 100644 index 0000000..09c3705 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SR86/in.yaml @@ -0,0 +1,2 @@ +key1: &a value +key2: &b *a diff --git a/Tests/Fixtures/yaml-test-suite/SR86/test.event b/Tests/Fixtures/yaml-test-suite/SR86/test.event new file mode 100644 index 0000000..5ce7dda --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SR86/test.event @@ -0,0 +1,6 @@ ++STR ++DOC ++MAP +=VAL :key1 +=VAL &a :value +=VAL :key2 diff --git a/Tests/Fixtures/yaml-test-suite/SSW6/in.json b/Tests/Fixtures/yaml-test-suite/SSW6/in.json new file mode 100644 index 0000000..fdc456c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SSW6/in.json @@ -0,0 +1 @@ +"here's to \"quotes\"" diff --git a/Tests/Fixtures/yaml-test-suite/SSW6/in.yaml b/Tests/Fixtures/yaml-test-suite/SSW6/in.yaml new file mode 100644 index 0000000..15d41f0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SSW6/in.yaml @@ -0,0 +1,2 @@ +--- +'here''s to "quotes"' diff --git a/Tests/Fixtures/yaml-test-suite/SSW6/test.event b/Tests/Fixtures/yaml-test-suite/SSW6/test.event new file mode 100644 index 0000000..7aa7100 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SSW6/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL 'here's to "quotes" +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/SU5Z/error b/Tests/Fixtures/yaml-test-suite/SU5Z/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/SU5Z/in.yaml b/Tests/Fixtures/yaml-test-suite/SU5Z/in.yaml new file mode 100644 index 0000000..ec3e02e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SU5Z/in.yaml @@ -0,0 +1 @@ +key: "value"# invalid comment diff --git a/Tests/Fixtures/yaml-test-suite/SU5Z/test.event b/Tests/Fixtures/yaml-test-suite/SU5Z/test.event new file mode 100644 index 0000000..77b4e02 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SU5Z/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :key +=VAL "value diff --git a/Tests/Fixtures/yaml-test-suite/SU74/error b/Tests/Fixtures/yaml-test-suite/SU74/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/SU74/in.yaml b/Tests/Fixtures/yaml-test-suite/SU74/in.yaml new file mode 100644 index 0000000..14f338e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SU74/in.yaml @@ -0,0 +1,2 @@ +key1: &alias value1 +&b *alias : value2 diff --git a/Tests/Fixtures/yaml-test-suite/SU74/test.event b/Tests/Fixtures/yaml-test-suite/SU74/test.event new file mode 100644 index 0000000..0ceec09 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SU74/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :key1 +=VAL &alias :value1 diff --git a/Tests/Fixtures/yaml-test-suite/SY6V/error b/Tests/Fixtures/yaml-test-suite/SY6V/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/SY6V/in.yaml b/Tests/Fixtures/yaml-test-suite/SY6V/in.yaml new file mode 100644 index 0000000..9912e67 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SY6V/in.yaml @@ -0,0 +1 @@ +&anchor - sequence entry diff --git a/Tests/Fixtures/yaml-test-suite/SY6V/test.event b/Tests/Fixtures/yaml-test-suite/SY6V/test.event new file mode 100644 index 0000000..e72d602 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SY6V/test.event @@ -0,0 +1 @@ ++STR diff --git a/Tests/Fixtures/yaml-test-suite/SYW4/in.json b/Tests/Fixtures/yaml-test-suite/SYW4/in.json new file mode 100644 index 0000000..a32fbec --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SYW4/in.json @@ -0,0 +1,5 @@ +{ + "hr": 65, + "avg": 0.278, + "rbi": 147 +} diff --git a/Tests/Fixtures/yaml-test-suite/SYW4/in.yaml b/Tests/Fixtures/yaml-test-suite/SYW4/in.yaml new file mode 100644 index 0000000..7b7ec94 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SYW4/in.yaml @@ -0,0 +1,3 @@ +hr: 65 # Home runs +avg: 0.278 # Batting average +rbi: 147 # Runs Batted In diff --git a/Tests/Fixtures/yaml-test-suite/SYW4/test.event b/Tests/Fixtures/yaml-test-suite/SYW4/test.event new file mode 100644 index 0000000..4868b00 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/SYW4/test.event @@ -0,0 +1,12 @@ ++STR ++DOC ++MAP +=VAL :hr +=VAL :65 +=VAL :avg +=VAL :0.278 +=VAL :rbi +=VAL :147 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/T26H/in.json b/Tests/Fixtures/yaml-test-suite/T26H/in.json new file mode 100644 index 0000000..6383f8d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T26H/in.json @@ -0,0 +1 @@ +"\n\nliteral\n \n\ntext\n" diff --git a/Tests/Fixtures/yaml-test-suite/T26H/in.yaml b/Tests/Fixtures/yaml-test-suite/T26H/in.yaml new file mode 100644 index 0000000..156b6d0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T26H/in.yaml @@ -0,0 +1,9 @@ +--- | + + + literal + + + text + + # Comment diff --git a/Tests/Fixtures/yaml-test-suite/T26H/test.event b/Tests/Fixtures/yaml-test-suite/T26H/test.event new file mode 100644 index 0000000..770297a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T26H/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL |\n\nliteral\n \n\ntext\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/T4YY/in.json b/Tests/Fixtures/yaml-test-suite/T4YY/in.json new file mode 100644 index 0000000..2dfab84 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T4YY/in.json @@ -0,0 +1 @@ +" 1st non-empty\n2nd non-empty 3rd non-empty " diff --git a/Tests/Fixtures/yaml-test-suite/T4YY/in.yaml b/Tests/Fixtures/yaml-test-suite/T4YY/in.yaml new file mode 100644 index 0000000..6cba7f1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T4YY/in.yaml @@ -0,0 +1,5 @@ +--- +' 1st non-empty + + 2nd non-empty + 3rd non-empty ' diff --git a/Tests/Fixtures/yaml-test-suite/T4YY/test.event b/Tests/Fixtures/yaml-test-suite/T4YY/test.event new file mode 100644 index 0000000..1ba7a09 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T4YY/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL ' 1st non-empty\n2nd non-empty 3rd non-empty +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/T5N4/in.json b/Tests/Fixtures/yaml-test-suite/T5N4/in.json new file mode 100644 index 0000000..2e190c6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T5N4/in.json @@ -0,0 +1 @@ +"literal\n\ttext\n" diff --git a/Tests/Fixtures/yaml-test-suite/T5N4/in.yaml b/Tests/Fixtures/yaml-test-suite/T5N4/in.yaml new file mode 100644 index 0000000..7ca4172 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T5N4/in.yaml @@ -0,0 +1,5 @@ +--- | + literal + text + + diff --git a/Tests/Fixtures/yaml-test-suite/T5N4/test.event b/Tests/Fixtures/yaml-test-suite/T5N4/test.event new file mode 100644 index 0000000..edf0168 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T5N4/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL |literal\n\ttext\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/T833/error b/Tests/Fixtures/yaml-test-suite/T833/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/T833/in.yaml b/Tests/Fixtures/yaml-test-suite/T833/in.yaml new file mode 100644 index 0000000..d35e395 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T833/in.yaml @@ -0,0 +1,4 @@ +--- +{ + foo: 1 + bar: 2 } diff --git a/Tests/Fixtures/yaml-test-suite/T833/test.event b/Tests/Fixtures/yaml-test-suite/T833/test.event new file mode 100644 index 0000000..d88db72 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/T833/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :foo diff --git a/Tests/Fixtures/yaml-test-suite/TD5N/error b/Tests/Fixtures/yaml-test-suite/TD5N/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/TD5N/in.yaml b/Tests/Fixtures/yaml-test-suite/TD5N/in.yaml new file mode 100644 index 0000000..bc6ccbb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TD5N/in.yaml @@ -0,0 +1,3 @@ +- item1 +- item2 +invalid diff --git a/Tests/Fixtures/yaml-test-suite/TD5N/test.event b/Tests/Fixtures/yaml-test-suite/TD5N/test.event new file mode 100644 index 0000000..fc4db33 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TD5N/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++SEQ +=VAL :item1 +=VAL :item2 diff --git a/Tests/Fixtures/yaml-test-suite/TE2A/in.json b/Tests/Fixtures/yaml-test-suite/TE2A/in.json new file mode 100644 index 0000000..1f5b290 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TE2A/in.json @@ -0,0 +1,5 @@ +{ + "block mapping": { + "key": "value" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/TE2A/in.yaml b/Tests/Fixtures/yaml-test-suite/TE2A/in.yaml new file mode 100644 index 0000000..2ef9084 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TE2A/in.yaml @@ -0,0 +1,2 @@ +block mapping: + key: value diff --git a/Tests/Fixtures/yaml-test-suite/TE2A/test.event b/Tests/Fixtures/yaml-test-suite/TE2A/test.event new file mode 100644 index 0000000..f97bcf5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TE2A/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++MAP +=VAL :block mapping ++MAP +=VAL :key +=VAL :value +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/TL85/in.json b/Tests/Fixtures/yaml-test-suite/TL85/in.json new file mode 100644 index 0000000..0fcc9db --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TL85/in.json @@ -0,0 +1 @@ +" foo\nbar\nbaz " diff --git a/Tests/Fixtures/yaml-test-suite/TL85/in.yaml b/Tests/Fixtures/yaml-test-suite/TL85/in.yaml new file mode 100644 index 0000000..d6af812 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TL85/in.yaml @@ -0,0 +1,7 @@ +" + foo + + bar + + baz +" diff --git a/Tests/Fixtures/yaml-test-suite/TL85/test.event b/Tests/Fixtures/yaml-test-suite/TL85/test.event new file mode 100644 index 0000000..8e49b19 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TL85/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL " foo\nbar\nbaz +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/TS54/in.json b/Tests/Fixtures/yaml-test-suite/TS54/in.json new file mode 100644 index 0000000..c63e7ba --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TS54/in.json @@ -0,0 +1 @@ +"ab cd\nef\n\ngh\n" diff --git a/Tests/Fixtures/yaml-test-suite/TS54/in.yaml b/Tests/Fixtures/yaml-test-suite/TS54/in.yaml new file mode 100644 index 0000000..f63944e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TS54/in.yaml @@ -0,0 +1,8 @@ +> + ab + cd + + ef + + + gh diff --git a/Tests/Fixtures/yaml-test-suite/TS54/test.event b/Tests/Fixtures/yaml-test-suite/TS54/test.event new file mode 100644 index 0000000..8651776 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/TS54/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL >ab cd\nef\n\ngh\n +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/U3C3/in.json b/Tests/Fixtures/yaml-test-suite/U3C3/in.json new file mode 100644 index 0000000..810c96e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U3C3/in.json @@ -0,0 +1 @@ +"foo" diff --git a/Tests/Fixtures/yaml-test-suite/U3C3/in.yaml b/Tests/Fixtures/yaml-test-suite/U3C3/in.yaml new file mode 100644 index 0000000..50f5ab9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U3C3/in.yaml @@ -0,0 +1,3 @@ +%TAG !yaml! tag:yaml.org,2002: +--- +!yaml!str "foo" diff --git a/Tests/Fixtures/yaml-test-suite/U3C3/test.event b/Tests/Fixtures/yaml-test-suite/U3C3/test.event new file mode 100644 index 0000000..b0ebd5f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U3C3/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL "foo +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/U3XV/in.json b/Tests/Fixtures/yaml-test-suite/U3XV/in.json new file mode 100644 index 0000000..7bc2e58 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U3XV/in.json @@ -0,0 +1,19 @@ +{ + "top1": { + "key1": "one" + }, + "top2": { + "key2": "two" + }, + "top3": { + "key3": "three" + }, + "top4": { + "key4": "four" + }, + "top5": { + "key5": "five" + }, + "top6": "six", + "top7": "seven" +} diff --git a/Tests/Fixtures/yaml-test-suite/U3XV/in.yaml b/Tests/Fixtures/yaml-test-suite/U3XV/in.yaml new file mode 100644 index 0000000..76660a8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U3XV/in.yaml @@ -0,0 +1,17 @@ +--- +top1: &node1 + &k1 key1: one +top2: &node2 # comment + key2: two +top3: + &k3 key3: three +top4: + &node4 + &k4 key4: four +top5: + &node5 + key5: five +top6: &val6 + six +top7: + &val7 seven diff --git a/Tests/Fixtures/yaml-test-suite/U3XV/test.event b/Tests/Fixtures/yaml-test-suite/U3XV/test.event new file mode 100644 index 0000000..4b924ae --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U3XV/test.event @@ -0,0 +1,35 @@ ++STR ++DOC --- ++MAP +=VAL :top1 ++MAP &node1 +=VAL &k1 :key1 +=VAL :one +-MAP +=VAL :top2 ++MAP &node2 +=VAL :key2 +=VAL :two +-MAP +=VAL :top3 ++MAP +=VAL &k3 :key3 +=VAL :three +-MAP +=VAL :top4 ++MAP &node4 +=VAL &k4 :key4 +=VAL :four +-MAP +=VAL :top5 ++MAP &node5 +=VAL :key5 +=VAL :five +-MAP +=VAL :top6 +=VAL &val6 :six +=VAL :top7 +=VAL &val7 :seven +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/U44R/error b/Tests/Fixtures/yaml-test-suite/U44R/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/U44R/in.yaml b/Tests/Fixtures/yaml-test-suite/U44R/in.yaml new file mode 100644 index 0000000..de68a32 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U44R/in.yaml @@ -0,0 +1,3 @@ +map: + key1: "quoted1" + key2: "bad indentation" diff --git a/Tests/Fixtures/yaml-test-suite/U44R/test.event b/Tests/Fixtures/yaml-test-suite/U44R/test.event new file mode 100644 index 0000000..416d1a1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U44R/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++MAP +=VAL :map ++MAP +=VAL :key1 +=VAL "quoted1 diff --git a/Tests/Fixtures/yaml-test-suite/U99R/error b/Tests/Fixtures/yaml-test-suite/U99R/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/U99R/in.yaml b/Tests/Fixtures/yaml-test-suite/U99R/in.yaml new file mode 100644 index 0000000..ba0c537 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U99R/in.yaml @@ -0,0 +1 @@ +- !!str, xxx diff --git a/Tests/Fixtures/yaml-test-suite/U99R/test.event b/Tests/Fixtures/yaml-test-suite/U99R/test.event new file mode 100644 index 0000000..fba9e07 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U99R/test.event @@ -0,0 +1,3 @@ ++STR ++DOC ++SEQ diff --git a/Tests/Fixtures/yaml-test-suite/U9NS/in.json b/Tests/Fixtures/yaml-test-suite/U9NS/in.json new file mode 100644 index 0000000..7bc7eac --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U9NS/in.json @@ -0,0 +1,10 @@ +{ + "time": "20:03:20", + "player": "Sammy Sosa", + "action": "strike (miss)" +} +{ + "time": "20:03:47", + "player": "Sammy Sosa", + "action": "grand slam" +} diff --git a/Tests/Fixtures/yaml-test-suite/U9NS/in.yaml b/Tests/Fixtures/yaml-test-suite/U9NS/in.yaml new file mode 100644 index 0000000..05e102d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U9NS/in.yaml @@ -0,0 +1,10 @@ +--- +time: 20:03:20 +player: Sammy Sosa +action: strike (miss) +... +--- +time: 20:03:47 +player: Sammy Sosa +action: grand slam +... diff --git a/Tests/Fixtures/yaml-test-suite/U9NS/test.event b/Tests/Fixtures/yaml-test-suite/U9NS/test.event new file mode 100644 index 0000000..2e2b745 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/U9NS/test.event @@ -0,0 +1,22 @@ ++STR ++DOC --- ++MAP +=VAL :time +=VAL :20:03:20 +=VAL :player +=VAL :Sammy Sosa +=VAL :action +=VAL :strike (miss) +-MAP +-DOC ... ++DOC --- ++MAP +=VAL :time +=VAL :20:03:47 +=VAL :player +=VAL :Sammy Sosa +=VAL :action +=VAL :grand slam +-MAP +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UDM2/in.json b/Tests/Fixtures/yaml-test-suite/UDM2/in.json new file mode 100644 index 0000000..7f2c93d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UDM2/in.json @@ -0,0 +1,5 @@ +[ + { + "url": "http://example.org" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/UDM2/in.yaml b/Tests/Fixtures/yaml-test-suite/UDM2/in.yaml new file mode 100644 index 0000000..fa95c05 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UDM2/in.yaml @@ -0,0 +1 @@ +- { url: http://example.org } diff --git a/Tests/Fixtures/yaml-test-suite/UDM2/test.event b/Tests/Fixtures/yaml-test-suite/UDM2/test.event new file mode 100644 index 0000000..4d9d6c8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UDM2/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ ++MAP {} +=VAL :url +=VAL :http://example.org +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UDR7/in.json b/Tests/Fixtures/yaml-test-suite/UDR7/in.json new file mode 100644 index 0000000..cecac0c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UDR7/in.json @@ -0,0 +1,10 @@ +{ + "sequence": [ + "one", + "two" + ], + "mapping": { + "sky": "blue", + "sea": "green" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/UDR7/in.yaml b/Tests/Fixtures/yaml-test-suite/UDR7/in.yaml new file mode 100644 index 0000000..df33847 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UDR7/in.yaml @@ -0,0 +1,2 @@ +sequence: [ one, two, ] +mapping: { sky: blue, sea: green } diff --git a/Tests/Fixtures/yaml-test-suite/UDR7/test.event b/Tests/Fixtures/yaml-test-suite/UDR7/test.event new file mode 100644 index 0000000..652120c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UDR7/test.event @@ -0,0 +1,18 @@ ++STR ++DOC ++MAP +=VAL :sequence ++SEQ [] +=VAL :one +=VAL :two +-SEQ +=VAL :mapping ++MAP {} +=VAL :sky +=VAL :blue +=VAL :sea +=VAL :green +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UGM3/in.json b/Tests/Fixtures/yaml-test-suite/UGM3/in.json new file mode 100644 index 0000000..a710161 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UGM3/in.json @@ -0,0 +1,41 @@ +{ + "invoice": 34843, + "date": "2001-01-23", + "bill-to": { + "given": "Chris", + "family": "Dumars", + "address": { + "lines": "458 Walkman Dr.\nSuite #292\n", + "city": "Royal Oak", + "state": "MI", + "postal": 48046 + } + }, + "ship-to": { + "given": "Chris", + "family": "Dumars", + "address": { + "lines": "458 Walkman Dr.\nSuite #292\n", + "city": "Royal Oak", + "state": "MI", + "postal": 48046 + } + }, + "product": [ + { + "sku": "BL394D", + "quantity": 4, + "description": "Basketball", + "price": 450 + }, + { + "sku": "BL4438H", + "quantity": 1, + "description": "Super Hoop", + "price": 2392 + } + ], + "tax": 251.42, + "total": 4443.52, + "comments": "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338." +} diff --git a/Tests/Fixtures/yaml-test-suite/UGM3/in.yaml b/Tests/Fixtures/yaml-test-suite/UGM3/in.yaml new file mode 100644 index 0000000..4625739 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UGM3/in.yaml @@ -0,0 +1,29 @@ +--- ! +invoice: 34843 +date : 2001-01-23 +bill-to: &id001 + given : Chris + family : Dumars + address: + lines: | + 458 Walkman Dr. + Suite #292 + city : Royal Oak + state : MI + postal : 48046 +ship-to: *id001 +product: + - sku : BL394D + quantity : 4 + description : Basketball + price : 450.00 + - sku : BL4438H + quantity : 1 + description : Super Hoop + price : 2392.00 +tax : 251.42 +total: 4443.52 +comments: + Late afternoon is best. + Backup contact is Nancy + Billsmer @ 338-4338. diff --git a/Tests/Fixtures/yaml-test-suite/UGM3/test.event b/Tests/Fixtures/yaml-test-suite/UGM3/test.event new file mode 100644 index 0000000..fdd1b5f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UGM3/test.event @@ -0,0 +1,59 @@ ++STR ++DOC --- ++MAP +=VAL :invoice +=VAL :34843 +=VAL :date +=VAL :2001-01-23 +=VAL :bill-to ++MAP &id001 +=VAL :given +=VAL :Chris +=VAL :family +=VAL :Dumars +=VAL :address ++MAP +=VAL :lines +=VAL |458 Walkman Dr.\nSuite #292\n +=VAL :city +=VAL :Royal Oak +=VAL :state +=VAL :MI +=VAL :postal +=VAL :48046 +-MAP +-MAP +=VAL :ship-to +=ALI *id001 +=VAL :product ++SEQ ++MAP +=VAL :sku +=VAL :BL394D +=VAL :quantity +=VAL :4 +=VAL :description +=VAL :Basketball +=VAL :price +=VAL :450.00 +-MAP ++MAP +=VAL :sku +=VAL :BL4438H +=VAL :quantity +=VAL :1 +=VAL :description +=VAL :Super Hoop +=VAL :price +=VAL :2392.00 +-MAP +-SEQ +=VAL :tax +=VAL :251.42 +=VAL :total +=VAL :4443.52 +=VAL :comments +=VAL :Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338. +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UKK6/00/in.yaml b/Tests/Fixtures/yaml-test-suite/UKK6/00/in.yaml new file mode 100644 index 0000000..e275119 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UKK6/00/in.yaml @@ -0,0 +1 @@ +- : diff --git a/Tests/Fixtures/yaml-test-suite/UKK6/00/test.event b/Tests/Fixtures/yaml-test-suite/UKK6/00/test.event new file mode 100644 index 0000000..ad12adf --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UKK6/00/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ ++MAP +=VAL : +=VAL : +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UKK6/01/in.json b/Tests/Fixtures/yaml-test-suite/UKK6/01/in.json new file mode 100644 index 0000000..f32d2e7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UKK6/01/in.json @@ -0,0 +1,3 @@ +{ + ":": null +} diff --git a/Tests/Fixtures/yaml-test-suite/UKK6/01/in.yaml b/Tests/Fixtures/yaml-test-suite/UKK6/01/in.yaml new file mode 100644 index 0000000..bef3763 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UKK6/01/in.yaml @@ -0,0 +1 @@ +:: diff --git a/Tests/Fixtures/yaml-test-suite/UKK6/01/test.event b/Tests/Fixtures/yaml-test-suite/UKK6/01/test.event new file mode 100644 index 0000000..2f9b508 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UKK6/01/test.event @@ -0,0 +1,8 @@ ++STR ++DOC ++MAP +=VAL :: +=VAL : +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UKK6/02/in.yaml b/Tests/Fixtures/yaml-test-suite/UKK6/02/in.yaml new file mode 100644 index 0000000..cdf4cb4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UKK6/02/in.yaml @@ -0,0 +1 @@ +! diff --git a/Tests/Fixtures/yaml-test-suite/UKK6/02/test.event b/Tests/Fixtures/yaml-test-suite/UKK6/02/test.event new file mode 100644 index 0000000..8370187 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UKK6/02/test.event @@ -0,0 +1,5 @@ ++STR ++DOC +=VAL : +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UT92/in.json b/Tests/Fixtures/yaml-test-suite/UT92/in.json new file mode 100644 index 0000000..587bbf4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UT92/in.json @@ -0,0 +1,4 @@ +{ + "matches %": 20 +} +null diff --git a/Tests/Fixtures/yaml-test-suite/UT92/in.yaml b/Tests/Fixtures/yaml-test-suite/UT92/in.yaml new file mode 100644 index 0000000..bc363b1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UT92/in.yaml @@ -0,0 +1,7 @@ +--- +{ matches +% : 20 } +... +--- +# Empty +... diff --git a/Tests/Fixtures/yaml-test-suite/UT92/test.event b/Tests/Fixtures/yaml-test-suite/UT92/test.event new file mode 100644 index 0000000..9a04f4d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UT92/test.event @@ -0,0 +1,11 @@ ++STR ++DOC --- ++MAP {} +=VAL :matches % +=VAL :20 +-MAP +-DOC ... ++DOC --- +=VAL : +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/UV7Q/in.json b/Tests/Fixtures/yaml-test-suite/UV7Q/in.json new file mode 100644 index 0000000..571dd36 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UV7Q/in.json @@ -0,0 +1,5 @@ +{ + "x": [ + "x x" + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/UV7Q/in.yaml b/Tests/Fixtures/yaml-test-suite/UV7Q/in.yaml new file mode 100644 index 0000000..7daa0a6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UV7Q/in.yaml @@ -0,0 +1,3 @@ +x: + - x + x diff --git a/Tests/Fixtures/yaml-test-suite/UV7Q/test.event b/Tests/Fixtures/yaml-test-suite/UV7Q/test.event new file mode 100644 index 0000000..a580d3d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/UV7Q/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :x ++SEQ +=VAL :x x +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/V55R/in.json b/Tests/Fixtures/yaml-test-suite/V55R/in.json new file mode 100644 index 0000000..b2810bc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/V55R/in.json @@ -0,0 +1,6 @@ +[ + "a", + "b", + "a", + "b" +] diff --git a/Tests/Fixtures/yaml-test-suite/V55R/in.yaml b/Tests/Fixtures/yaml-test-suite/V55R/in.yaml new file mode 100644 index 0000000..b3c45b5 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/V55R/in.yaml @@ -0,0 +1,4 @@ +- &a a +- &b b +- *a +- *b diff --git a/Tests/Fixtures/yaml-test-suite/V55R/test.event b/Tests/Fixtures/yaml-test-suite/V55R/test.event new file mode 100644 index 0000000..d60de06 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/V55R/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++SEQ +=VAL &a :a +=VAL &b :b +=ALI *a +=ALI *b +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/V9D5/in.yaml b/Tests/Fixtures/yaml-test-suite/V9D5/in.yaml new file mode 100644 index 0000000..d675cfd --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/V9D5/in.yaml @@ -0,0 +1,3 @@ +- sun: yellow +- ? earth: blue + : moon: white diff --git a/Tests/Fixtures/yaml-test-suite/V9D5/test.event b/Tests/Fixtures/yaml-test-suite/V9D5/test.event new file mode 100644 index 0000000..e682110 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/V9D5/test.event @@ -0,0 +1,20 @@ ++STR ++DOC ++SEQ ++MAP +=VAL :sun +=VAL :yellow +-MAP ++MAP ++MAP +=VAL :earth +=VAL :blue +-MAP ++MAP +=VAL :moon +=VAL :white +-MAP +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/VJP3/00/error b/Tests/Fixtures/yaml-test-suite/VJP3/00/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/VJP3/00/in.yaml b/Tests/Fixtures/yaml-test-suite/VJP3/00/in.yaml new file mode 100644 index 0000000..79c6eda --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/VJP3/00/in.yaml @@ -0,0 +1,5 @@ +k: { +k +: +v +} diff --git a/Tests/Fixtures/yaml-test-suite/VJP3/00/test.event b/Tests/Fixtures/yaml-test-suite/VJP3/00/test.event new file mode 100644 index 0000000..1a791d8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/VJP3/00/test.event @@ -0,0 +1,5 @@ ++STR ++DOC ++MAP +=VAL :k ++MAP {} diff --git a/Tests/Fixtures/yaml-test-suite/VJP3/01/in.json b/Tests/Fixtures/yaml-test-suite/VJP3/01/in.json new file mode 100644 index 0000000..ebcd68c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/VJP3/01/in.json @@ -0,0 +1,5 @@ +{ + "k" : { + "k" : "v" + } +} diff --git a/Tests/Fixtures/yaml-test-suite/VJP3/01/in.yaml b/Tests/Fixtures/yaml-test-suite/VJP3/01/in.yaml new file mode 100644 index 0000000..1d71c2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/VJP3/01/in.yaml @@ -0,0 +1,5 @@ +k: { + k + : + v + } diff --git a/Tests/Fixtures/yaml-test-suite/VJP3/01/test.event b/Tests/Fixtures/yaml-test-suite/VJP3/01/test.event new file mode 100644 index 0000000..b515ee4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/VJP3/01/test.event @@ -0,0 +1,11 @@ ++STR ++DOC ++MAP +=VAL :k ++MAP {} +=VAL :k +=VAL :v +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/W42U/in.json b/Tests/Fixtures/yaml-test-suite/W42U/in.json new file mode 100644 index 0000000..b277eb8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W42U/in.json @@ -0,0 +1,11 @@ +[ + null, + "block node\n", + [ + "one", + "two" + ], + { + "one": "two" + } +] diff --git a/Tests/Fixtures/yaml-test-suite/W42U/in.yaml b/Tests/Fixtures/yaml-test-suite/W42U/in.yaml new file mode 100644 index 0000000..35ac923 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W42U/in.yaml @@ -0,0 +1,6 @@ +- # Empty +- | + block node +- - one # Compact + - two # sequence +- one: two # Compact mapping diff --git a/Tests/Fixtures/yaml-test-suite/W42U/test.event b/Tests/Fixtures/yaml-test-suite/W42U/test.event new file mode 100644 index 0000000..20ed214 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W42U/test.event @@ -0,0 +1,16 @@ ++STR ++DOC ++SEQ +=VAL : +=VAL |block node\n ++SEQ +=VAL :one +=VAL :two +-SEQ ++MAP +=VAL :one +=VAL :two +-MAP +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/W4TN/in.json b/Tests/Fixtures/yaml-test-suite/W4TN/in.json new file mode 100644 index 0000000..c9dfdfe --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W4TN/in.json @@ -0,0 +1,2 @@ +"%!PS-Adobe-2.0\n" +null diff --git a/Tests/Fixtures/yaml-test-suite/W4TN/in.yaml b/Tests/Fixtures/yaml-test-suite/W4TN/in.yaml new file mode 100644 index 0000000..82de01b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W4TN/in.yaml @@ -0,0 +1,8 @@ +%YAML 1.2 +--- | +%!PS-Adobe-2.0 +... +%YAML 1.2 +--- +# Empty +... diff --git a/Tests/Fixtures/yaml-test-suite/W4TN/test.event b/Tests/Fixtures/yaml-test-suite/W4TN/test.event new file mode 100644 index 0000000..c1fdc9e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W4TN/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- +=VAL |%!PS-Adobe-2.0\n +-DOC ... ++DOC --- +=VAL : +-DOC ... +-STR diff --git a/Tests/Fixtures/yaml-test-suite/W5VH/in.json b/Tests/Fixtures/yaml-test-suite/W5VH/in.json new file mode 100644 index 0000000..d2a0de4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W5VH/in.json @@ -0,0 +1,4 @@ +{ + "a": "scalar a", + "b": "scalar a" +} diff --git a/Tests/Fixtures/yaml-test-suite/W5VH/in.yaml b/Tests/Fixtures/yaml-test-suite/W5VH/in.yaml new file mode 100644 index 0000000..43c7a15 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W5VH/in.yaml @@ -0,0 +1,2 @@ +a: &:@*!$": scalar a +b: *:@*!$": diff --git a/Tests/Fixtures/yaml-test-suite/W5VH/test.event b/Tests/Fixtures/yaml-test-suite/W5VH/test.event new file mode 100644 index 0000000..e09fdf8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W5VH/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL &:@*!$": :scalar a +=VAL :b +=ALI *:@*!$": +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/W9L4/error b/Tests/Fixtures/yaml-test-suite/W9L4/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/W9L4/in.yaml b/Tests/Fixtures/yaml-test-suite/W9L4/in.yaml new file mode 100644 index 0000000..7b15d0c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W9L4/in.yaml @@ -0,0 +1,5 @@ +--- +block scalar: | + + more spaces at the beginning + are invalid diff --git a/Tests/Fixtures/yaml-test-suite/W9L4/test.event b/Tests/Fixtures/yaml-test-suite/W9L4/test.event new file mode 100644 index 0000000..7f1aaeb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/W9L4/test.event @@ -0,0 +1,4 @@ ++STR ++DOC --- ++MAP +=VAL :block scalar diff --git a/Tests/Fixtures/yaml-test-suite/WZ62/in.json b/Tests/Fixtures/yaml-test-suite/WZ62/in.json new file mode 100644 index 0000000..e1b8322 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/WZ62/in.json @@ -0,0 +1,4 @@ +{ + "foo": "", + "": "bar" +} diff --git a/Tests/Fixtures/yaml-test-suite/WZ62/in.yaml b/Tests/Fixtures/yaml-test-suite/WZ62/in.yaml new file mode 100644 index 0000000..aa86103 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/WZ62/in.yaml @@ -0,0 +1,4 @@ +{ + foo : !!str, + !!str : bar, +} diff --git a/Tests/Fixtures/yaml-test-suite/WZ62/test.event b/Tests/Fixtures/yaml-test-suite/WZ62/test.event new file mode 100644 index 0000000..d127c08 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/WZ62/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP {} +=VAL :foo +=VAL : +=VAL : +=VAL :bar +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/X38W/in.yaml b/Tests/Fixtures/yaml-test-suite/X38W/in.yaml new file mode 100644 index 0000000..4772110 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/X38W/in.yaml @@ -0,0 +1 @@ +{ &a [a, &b b]: *b, *a : [c, *b, d]} diff --git a/Tests/Fixtures/yaml-test-suite/X38W/test.event b/Tests/Fixtures/yaml-test-suite/X38W/test.event new file mode 100644 index 0000000..2d6a86d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/X38W/test.event @@ -0,0 +1,17 @@ ++STR ++DOC ++MAP {} ++SEQ [] &a +=VAL :a +=VAL &b :b +-SEQ +=ALI *b +=ALI *a ++SEQ [] +=VAL :c +=ALI *b +=VAL :d +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/X4QW/error b/Tests/Fixtures/yaml-test-suite/X4QW/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/X4QW/in.yaml b/Tests/Fixtures/yaml-test-suite/X4QW/in.yaml new file mode 100644 index 0000000..0444f18 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/X4QW/in.yaml @@ -0,0 +1,2 @@ +block: ># comment + scalar diff --git a/Tests/Fixtures/yaml-test-suite/X4QW/test.event b/Tests/Fixtures/yaml-test-suite/X4QW/test.event new file mode 100644 index 0000000..a0e77d6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/X4QW/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :block diff --git a/Tests/Fixtures/yaml-test-suite/X8DW/in.json b/Tests/Fixtures/yaml-test-suite/X8DW/in.json new file mode 100644 index 0000000..7a9e864 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/X8DW/in.json @@ -0,0 +1,3 @@ +{ + "key": "value" +} diff --git a/Tests/Fixtures/yaml-test-suite/X8DW/in.yaml b/Tests/Fixtures/yaml-test-suite/X8DW/in.yaml new file mode 100644 index 0000000..22911fc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/X8DW/in.yaml @@ -0,0 +1,4 @@ +--- +? key +# comment +: value diff --git a/Tests/Fixtures/yaml-test-suite/X8DW/test.event b/Tests/Fixtures/yaml-test-suite/X8DW/test.event new file mode 100644 index 0000000..16023e0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/X8DW/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :key +=VAL :value +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/XLQ9/in.json b/Tests/Fixtures/yaml-test-suite/XLQ9/in.json new file mode 100644 index 0000000..20ec09f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XLQ9/in.json @@ -0,0 +1 @@ +"scalar %YAML 1.2" diff --git a/Tests/Fixtures/yaml-test-suite/XLQ9/in.yaml b/Tests/Fixtures/yaml-test-suite/XLQ9/in.yaml new file mode 100644 index 0000000..dbe36b9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XLQ9/in.yaml @@ -0,0 +1,3 @@ +--- +scalar +%YAML 1.2 diff --git a/Tests/Fixtures/yaml-test-suite/XLQ9/test.event b/Tests/Fixtures/yaml-test-suite/XLQ9/test.event new file mode 100644 index 0000000..820a33c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XLQ9/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- +=VAL :scalar %YAML 1.2 +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/XV9V/in.json b/Tests/Fixtures/yaml-test-suite/XV9V/in.json new file mode 100644 index 0000000..41a96a1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XV9V/in.json @@ -0,0 +1,4 @@ +{ + "Folding": "Empty line\nas a line feed", + "Chomping": "Clipped empty lines\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/XV9V/in.yaml b/Tests/Fixtures/yaml-test-suite/XV9V/in.yaml new file mode 100644 index 0000000..c7775c4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XV9V/in.yaml @@ -0,0 +1,8 @@ +Folding: + "Empty line + + as a line feed" +Chomping: | + Clipped empty lines + + diff --git a/Tests/Fixtures/yaml-test-suite/XV9V/test.event b/Tests/Fixtures/yaml-test-suite/XV9V/test.event new file mode 100644 index 0000000..1acf1f8 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XV9V/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :Folding +=VAL "Empty line\nas a line feed +=VAL :Chomping +=VAL |Clipped empty lines\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/XW4D/in.yaml b/Tests/Fixtures/yaml-test-suite/XW4D/in.yaml new file mode 100644 index 0000000..4fcc93e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XW4D/in.yaml @@ -0,0 +1,16 @@ +a: "double + quotes" # lala +b: plain + value # lala +c : #lala + d +? # lala + - seq1 +: # lala + - #lala + seq2 +e: + &node # lala + - x: y +block: > # lala + abcde diff --git a/Tests/Fixtures/yaml-test-suite/XW4D/test.event b/Tests/Fixtures/yaml-test-suite/XW4D/test.event new file mode 100644 index 0000000..fc2031d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/XW4D/test.event @@ -0,0 +1,27 @@ ++STR ++DOC ++MAP +=VAL :a +=VAL "double quotes +=VAL :b +=VAL :plain value +=VAL :c +=VAL :d ++SEQ +=VAL :seq1 +-SEQ ++SEQ +=VAL :seq2 +-SEQ +=VAL :e ++SEQ &node ++MAP +=VAL :x +=VAL :y +-MAP +-SEQ +=VAL :block +=VAL >abcde\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Y2GN/in.json b/Tests/Fixtures/yaml-test-suite/Y2GN/in.json new file mode 100644 index 0000000..7a9e864 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y2GN/in.json @@ -0,0 +1,3 @@ +{ + "key": "value" +} diff --git a/Tests/Fixtures/yaml-test-suite/Y2GN/in.yaml b/Tests/Fixtures/yaml-test-suite/Y2GN/in.yaml new file mode 100644 index 0000000..ec2bb92 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y2GN/in.yaml @@ -0,0 +1,2 @@ +--- +key: &an:chor value diff --git a/Tests/Fixtures/yaml-test-suite/Y2GN/test.event b/Tests/Fixtures/yaml-test-suite/Y2GN/test.event new file mode 100644 index 0000000..8cc245f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y2GN/test.event @@ -0,0 +1,8 @@ ++STR ++DOC --- ++MAP +=VAL :key +=VAL &an:chor :value +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/000/error b/Tests/Fixtures/yaml-test-suite/Y79Y/000/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/000/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/000/in.yaml new file mode 100644 index 0000000..4e55271 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/000/in.yaml @@ -0,0 +1,3 @@ +foo: | + +bar: 1 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/000/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/000/test.event new file mode 100644 index 0000000..a29c31a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/000/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :foo diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/001/in.json b/Tests/Fixtures/yaml-test-suite/Y79Y/001/in.json new file mode 100644 index 0000000..687c550 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/001/in.json @@ -0,0 +1,4 @@ +{ + "foo": "\t\n", + "bar": 1 +} diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/001/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/001/in.yaml new file mode 100644 index 0000000..3c2e414 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/001/in.yaml @@ -0,0 +1,3 @@ +foo: | + +bar: 1 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/001/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/001/test.event new file mode 100644 index 0000000..1bd7876 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/001/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :foo +=VAL |\t\n +=VAL :bar +=VAL :1 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/002/in.json b/Tests/Fixtures/yaml-test-suite/Y79Y/002/in.json new file mode 100644 index 0000000..4e8764e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/002/in.json @@ -0,0 +1,5 @@ +[ + [ + "foo" + ] +] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/002/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/002/in.yaml new file mode 100644 index 0000000..6b6ad5d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/002/in.yaml @@ -0,0 +1,4 @@ +- [ + + foo + ] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/002/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/002/test.event new file mode 100644 index 0000000..2401c05 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/002/test.event @@ -0,0 +1,9 @@ ++STR ++DOC ++SEQ ++SEQ [] +=VAL :foo +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/003/error b/Tests/Fixtures/yaml-test-suite/Y79Y/003/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/003/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/003/in.yaml new file mode 100644 index 0000000..8585471 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/003/in.yaml @@ -0,0 +1,4 @@ +- [ + foo, + foo + ] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/003/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/003/test.event new file mode 100644 index 0000000..ff5ba2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/003/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/004/error b/Tests/Fixtures/yaml-test-suite/Y79Y/004/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/004/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/004/in.yaml new file mode 100644 index 0000000..0806e5a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/004/in.yaml @@ -0,0 +1 @@ +- - diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/004/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/004/test.event new file mode 100644 index 0000000..ff5ba2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/004/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/005/error b/Tests/Fixtures/yaml-test-suite/Y79Y/005/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/005/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/005/in.yaml new file mode 100644 index 0000000..ec67404 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/005/in.yaml @@ -0,0 +1 @@ +- - diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/005/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/005/test.event new file mode 100644 index 0000000..ff5ba2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/005/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/006/error b/Tests/Fixtures/yaml-test-suite/Y79Y/006/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/006/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/006/in.yaml new file mode 100644 index 0000000..5c42b44 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/006/in.yaml @@ -0,0 +1 @@ +? - diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/006/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/006/test.event new file mode 100644 index 0000000..ff5ba2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/006/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/007/error b/Tests/Fixtures/yaml-test-suite/Y79Y/007/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/007/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/007/in.yaml new file mode 100644 index 0000000..4f3691a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/007/in.yaml @@ -0,0 +1,2 @@ +? - +: - diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/007/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/007/test.event new file mode 100644 index 0000000..ff5ba2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/007/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/008/error b/Tests/Fixtures/yaml-test-suite/Y79Y/008/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/008/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/008/in.yaml new file mode 100644 index 0000000..b9a50bb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/008/in.yaml @@ -0,0 +1 @@ +? key: diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/008/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/008/test.event new file mode 100644 index 0000000..ff5ba2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/008/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/009/error b/Tests/Fixtures/yaml-test-suite/Y79Y/009/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/009/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/009/in.yaml new file mode 100644 index 0000000..851a621 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/009/in.yaml @@ -0,0 +1,2 @@ +? key: +: key: diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/009/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/009/test.event new file mode 100644 index 0000000..ff5ba2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/009/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/010/in.json b/Tests/Fixtures/yaml-test-suite/Y79Y/010/in.json new file mode 100644 index 0000000..4c1600d --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/010/in.json @@ -0,0 +1,3 @@ +[ + -1 +] diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/010/in.yaml b/Tests/Fixtures/yaml-test-suite/Y79Y/010/in.yaml new file mode 100644 index 0000000..763ef1b --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/010/in.yaml @@ -0,0 +1 @@ +- -1 diff --git a/Tests/Fixtures/yaml-test-suite/Y79Y/010/test.event b/Tests/Fixtures/yaml-test-suite/Y79Y/010/test.event new file mode 100644 index 0000000..8d71c76 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Y79Y/010/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ +=VAL :-1 +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/YD5X/in.json b/Tests/Fixtures/yaml-test-suite/YD5X/in.json new file mode 100644 index 0000000..45d384a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/YD5X/in.json @@ -0,0 +1,17 @@ +[ + [ + "name", + "hr", + "avg" + ], + [ + "Mark McGwire", + 65, + 0.278 + ], + [ + "Sammy Sosa", + 63, + 0.288 + ] +] diff --git a/Tests/Fixtures/yaml-test-suite/YD5X/in.yaml b/Tests/Fixtures/yaml-test-suite/YD5X/in.yaml new file mode 100644 index 0000000..cdd7770 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/YD5X/in.yaml @@ -0,0 +1,3 @@ +- [name , hr, avg ] +- [Mark McGwire, 65, 0.278] +- [Sammy Sosa , 63, 0.288] diff --git a/Tests/Fixtures/yaml-test-suite/YD5X/test.event b/Tests/Fixtures/yaml-test-suite/YD5X/test.event new file mode 100644 index 0000000..2fa8b2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/YD5X/test.event @@ -0,0 +1,21 @@ ++STR ++DOC ++SEQ ++SEQ [] +=VAL :name +=VAL :hr +=VAL :avg +-SEQ ++SEQ [] +=VAL :Mark McGwire +=VAL :65 +=VAL :0.278 +-SEQ ++SEQ [] +=VAL :Sammy Sosa +=VAL :63 +=VAL :0.288 +-SEQ +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/YJV2/error b/Tests/Fixtures/yaml-test-suite/YJV2/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/YJV2/in.yaml b/Tests/Fixtures/yaml-test-suite/YJV2/in.yaml new file mode 100644 index 0000000..4cce7dc --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/YJV2/in.yaml @@ -0,0 +1 @@ +[-] diff --git a/Tests/Fixtures/yaml-test-suite/YJV2/test.event b/Tests/Fixtures/yaml-test-suite/YJV2/test.event new file mode 100644 index 0000000..b1282c7 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/YJV2/test.event @@ -0,0 +1,3 @@ ++STR ++DOC ++SEQ [] diff --git a/Tests/Fixtures/yaml-test-suite/Z67P/in.json b/Tests/Fixtures/yaml-test-suite/Z67P/in.json new file mode 100644 index 0000000..f1eedb0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Z67P/in.json @@ -0,0 +1,4 @@ +{ + "literal": "value\n", + "folded": "value\n" +} diff --git a/Tests/Fixtures/yaml-test-suite/Z67P/in.yaml b/Tests/Fixtures/yaml-test-suite/Z67P/in.yaml new file mode 100644 index 0000000..69122ac --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Z67P/in.yaml @@ -0,0 +1,4 @@ +literal: |2 + value +folded: !foo >1 + value diff --git a/Tests/Fixtures/yaml-test-suite/Z67P/test.event b/Tests/Fixtures/yaml-test-suite/Z67P/test.event new file mode 100644 index 0000000..fcebe87 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Z67P/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL :literal +=VAL |value\n +=VAL :folded +=VAL >value\n +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/Z9M4/in.json b/Tests/Fixtures/yaml-test-suite/Z9M4/in.json new file mode 100644 index 0000000..248299a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Z9M4/in.json @@ -0,0 +1,3 @@ +[ + "bar" +] diff --git a/Tests/Fixtures/yaml-test-suite/Z9M4/in.yaml b/Tests/Fixtures/yaml-test-suite/Z9M4/in.yaml new file mode 100644 index 0000000..eedfe04 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Z9M4/in.yaml @@ -0,0 +1,3 @@ +%TAG !e! tag:example.com,2000:app/ +--- +- !e!foo "bar" diff --git a/Tests/Fixtures/yaml-test-suite/Z9M4/test.event b/Tests/Fixtures/yaml-test-suite/Z9M4/test.event new file mode 100644 index 0000000..9b9478c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/Z9M4/test.event @@ -0,0 +1,7 @@ ++STR ++DOC --- ++SEQ +=VAL "bar +-SEQ +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/ZCZ6/error b/Tests/Fixtures/yaml-test-suite/ZCZ6/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/ZCZ6/in.yaml b/Tests/Fixtures/yaml-test-suite/ZCZ6/in.yaml new file mode 100644 index 0000000..c47fb7c --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZCZ6/in.yaml @@ -0,0 +1 @@ +a: b: c: d diff --git a/Tests/Fixtures/yaml-test-suite/ZCZ6/test.event b/Tests/Fixtures/yaml-test-suite/ZCZ6/test.event new file mode 100644 index 0000000..21d292e --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZCZ6/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++MAP +=VAL :a diff --git a/Tests/Fixtures/yaml-test-suite/ZF4X/in.json b/Tests/Fixtures/yaml-test-suite/ZF4X/in.json new file mode 100644 index 0000000..425e548 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZF4X/in.json @@ -0,0 +1,10 @@ +{ + "Mark McGwire": { + "hr": 65, + "avg": 0.278 + }, + "Sammy Sosa": { + "hr": 63, + "avg": 0.288 + } +} diff --git a/Tests/Fixtures/yaml-test-suite/ZF4X/in.yaml b/Tests/Fixtures/yaml-test-suite/ZF4X/in.yaml new file mode 100644 index 0000000..7a957b2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZF4X/in.yaml @@ -0,0 +1,5 @@ +Mark McGwire: {hr: 65, avg: 0.278} +Sammy Sosa: { + hr: 63, + avg: 0.288 + } diff --git a/Tests/Fixtures/yaml-test-suite/ZF4X/test.event b/Tests/Fixtures/yaml-test-suite/ZF4X/test.event new file mode 100644 index 0000000..8d0d5ab --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZF4X/test.event @@ -0,0 +1,20 @@ ++STR ++DOC ++MAP +=VAL :Mark McGwire ++MAP {} +=VAL :hr +=VAL :65 +=VAL :avg +=VAL :0.278 +-MAP +=VAL :Sammy Sosa ++MAP {} +=VAL :hr +=VAL :63 +=VAL :avg +=VAL :0.288 +-MAP +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/ZH7C/in.json b/Tests/Fixtures/yaml-test-suite/ZH7C/in.json new file mode 100644 index 0000000..bc92764 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZH7C/in.json @@ -0,0 +1,4 @@ +{ + "a": "b", + "c": "d" +} diff --git a/Tests/Fixtures/yaml-test-suite/ZH7C/in.yaml b/Tests/Fixtures/yaml-test-suite/ZH7C/in.yaml new file mode 100644 index 0000000..64d718f --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZH7C/in.yaml @@ -0,0 +1,2 @@ +&a a: b +c: &d d diff --git a/Tests/Fixtures/yaml-test-suite/ZH7C/test.event b/Tests/Fixtures/yaml-test-suite/ZH7C/test.event new file mode 100644 index 0000000..f94dba0 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZH7C/test.event @@ -0,0 +1,10 @@ ++STR ++DOC ++MAP +=VAL &a :a +=VAL :b +=VAL :c +=VAL &d :d +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/ZK9H/in.json b/Tests/Fixtures/yaml-test-suite/ZK9H/in.json new file mode 100644 index 0000000..69b8133 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZK9H/in.json @@ -0,0 +1,9 @@ +{ + "key": [ + [ + [ + "value" + ] + ] + ] +} diff --git a/Tests/Fixtures/yaml-test-suite/ZK9H/in.yaml b/Tests/Fixtures/yaml-test-suite/ZK9H/in.yaml new file mode 100644 index 0000000..eb177c6 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZK9H/in.yaml @@ -0,0 +1,4 @@ +{ key: [[[ + value + ]]] +} diff --git a/Tests/Fixtures/yaml-test-suite/ZK9H/test.event b/Tests/Fixtures/yaml-test-suite/ZK9H/test.event new file mode 100644 index 0000000..5462946 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZK9H/test.event @@ -0,0 +1,14 @@ ++STR ++DOC ++MAP {} +=VAL :key ++SEQ [] ++SEQ [] ++SEQ [] +=VAL :value +-SEQ +-SEQ +-SEQ +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/ZL4Z/error b/Tests/Fixtures/yaml-test-suite/ZL4Z/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/ZL4Z/in.yaml b/Tests/Fixtures/yaml-test-suite/ZL4Z/in.yaml new file mode 100644 index 0000000..798dbbb --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZL4Z/in.yaml @@ -0,0 +1,2 @@ +--- +a: 'b': c diff --git a/Tests/Fixtures/yaml-test-suite/ZL4Z/test.event b/Tests/Fixtures/yaml-test-suite/ZL4Z/test.event new file mode 100644 index 0000000..cb568a4 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZL4Z/test.event @@ -0,0 +1,5 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL 'b diff --git a/Tests/Fixtures/yaml-test-suite/ZVH3/error b/Tests/Fixtures/yaml-test-suite/ZVH3/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/ZVH3/in.yaml b/Tests/Fixtures/yaml-test-suite/ZVH3/in.yaml new file mode 100644 index 0000000..9db12c9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZVH3/in.yaml @@ -0,0 +1,2 @@ +- key: value + - item1 diff --git a/Tests/Fixtures/yaml-test-suite/ZVH3/test.event b/Tests/Fixtures/yaml-test-suite/ZVH3/test.event new file mode 100644 index 0000000..c38cb76 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZVH3/test.event @@ -0,0 +1,7 @@ ++STR ++DOC ++SEQ ++MAP +=VAL :key +=VAL :value +-MAP diff --git a/Tests/Fixtures/yaml-test-suite/ZWK4/in.json b/Tests/Fixtures/yaml-test-suite/ZWK4/in.json new file mode 100644 index 0000000..ede92b9 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZWK4/in.json @@ -0,0 +1,5 @@ +{ + "a": 1, + "b": null, + "c": 3 +} diff --git a/Tests/Fixtures/yaml-test-suite/ZWK4/in.yaml b/Tests/Fixtures/yaml-test-suite/ZWK4/in.yaml new file mode 100644 index 0000000..b6fca2a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZWK4/in.yaml @@ -0,0 +1,4 @@ +--- +a: 1 +? b +&anchor c: 3 diff --git a/Tests/Fixtures/yaml-test-suite/ZWK4/test.event b/Tests/Fixtures/yaml-test-suite/ZWK4/test.event new file mode 100644 index 0000000..ccd5f7a --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZWK4/test.event @@ -0,0 +1,12 @@ ++STR ++DOC --- ++MAP +=VAL :a +=VAL :1 +=VAL :b +=VAL : +=VAL &anchor :c +=VAL :3 +-MAP +-DOC +-STR diff --git a/Tests/Fixtures/yaml-test-suite/ZXT5/error b/Tests/Fixtures/yaml-test-suite/ZXT5/error new file mode 100644 index 0000000..e69de29 diff --git a/Tests/Fixtures/yaml-test-suite/ZXT5/in.yaml b/Tests/Fixtures/yaml-test-suite/ZXT5/in.yaml new file mode 100644 index 0000000..be1ccf2 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZXT5/in.yaml @@ -0,0 +1,2 @@ +[ "key" + :value ] diff --git a/Tests/Fixtures/yaml-test-suite/ZXT5/test.event b/Tests/Fixtures/yaml-test-suite/ZXT5/test.event new file mode 100644 index 0000000..352ead1 --- /dev/null +++ b/Tests/Fixtures/yaml-test-suite/ZXT5/test.event @@ -0,0 +1,4 @@ ++STR ++DOC ++SEQ [] +=VAL "key diff --git a/Tests/LibYAMLCharacterClassTests.swift b/Tests/LibYAMLCharacterClassTests.swift new file mode 100644 index 0000000..6f08c19 --- /dev/null +++ b/Tests/LibYAMLCharacterClassTests.swift @@ -0,0 +1,65 @@ +@testable import PureYAML +import Testing + +/// Verifies the ported character-class predicates match libyaml's `IS_*` macros, +/// including end-of-input as `nil` and the multi-byte line breaks. +@Suite("LibYAML Character Class") +struct LibYAMLCharacterClassTests { + private typealias Classify = PureYAML.Parsing.LibYAML.CharacterClass + + @Test("end of input is Z and a break, nothing else") + func test_endOfInput() { + #expect(Classify.isZ(nil)) + #expect(Classify.isBreakZ(nil)) + #expect(Classify.isBlankZ(nil)) + #expect(!Classify.isBreak(nil)) + #expect(!Classify.isBlank(nil)) + #expect(!Classify.isAlpha(nil)) + } + + @Test("blanks are space and tab only") + func test_blank() { + #expect(Classify.isSpace(" ")) + #expect(Classify.isTab("\t")) + #expect(Classify.isBlank(" ")) + #expect(Classify.isBlank("\t")) + #expect(!Classify.isBlank("\n")) + #expect(!Classify.isBlank("x")) + } + + @Test("line breaks include CR, LF, NEL, LS, PS") + func test_break() { + for scalar in ["\r", "\n", "\u{85}", "\u{2028}", "\u{2029}"] as [Unicode.Scalar] { + #expect(Classify.isBreak(scalar)) + #expect(Classify.isBreakZ(scalar)) + #expect(Classify.isBlankZ(scalar)) + } + #expect(!Classify.isBreak(" ")) + #expect(!Classify.isBreak("x")) + } + + @Test("alpha is alnum plus underscore and hyphen") + func test_alpha() { + for scalar in ["0", "9", "A", "Z", "a", "z", "_", "-"] as [Unicode.Scalar] { + #expect(Classify.isAlpha(scalar)) + } + #expect(!Classify.isAlpha(".")) + #expect(!Classify.isAlpha(" ")) + #expect(Classify.isDigit("5")) + #expect(!Classify.isDigit("a")) + #expect(Classify.isHex("f")) + #expect(Classify.isHex("9")) + #expect(!Classify.isHex("g")) + } + + @Test("ascii and printable boundaries") + func test_asciiPrintable() { + #expect(Classify.isASCII("\u{7F}")) + #expect(!Classify.isASCII("\u{80}")) + #expect(Classify.isPrintable("\t")) + #expect(Classify.isPrintable("A")) + #expect(Classify.isPrintable("\u{85}")) + #expect(!Classify.isPrintable("\u{0}")) + #expect(!Classify.isPrintable("\u{1F}")) + } +} diff --git a/Tests/LibYAMLIndentEngineTests.swift b/Tests/LibYAMLIndentEngineTests.swift new file mode 100644 index 0000000..024bf6e --- /dev/null +++ b/Tests/LibYAMLIndentEngineTests.swift @@ -0,0 +1,58 @@ +@testable import PureYAML +import Testing + +/// Verifies the ported indentation engine reproduces libyaml's `roll_indent` / +/// `unroll_indent` behavior, in particular the rule that fixes the block-mapping +/// bug: a block collection opens only when content is strictly more indented than +/// the current level. +@Suite("LibYAML Indent Engine") +struct LibYAMLIndentEngineTests { + private let mark = PureYAML.Parsing.Mark.start + + @Test("a same-column key after an empty value is a sibling, not nested") + func test_sameColumnKeyIsSibling() { + // `- a:` then ` b: c`: the `-` opens a sequence at column 0; the key `a` + // opens a mapping at column 2; `a` has no value; `b` arrives at column 2. + var engine = PureYAML.Parsing.LibYAML.IndentEngine() + engine.rollIndent(column: 0, number: -1, type: .blockSequenceStart, mark: mark) + engine.rollIndent(column: 2, number: -1, type: .blockMappingStart, mark: mark) + engine.unrollIndent(column: 2, mark: mark) + engine.rollIndent(column: 2, number: -1, type: .blockMappingStart, mark: mark) + engine.unrollIndent(column: -1, mark: mark) + + // One sequence, one mapping (b is a sibling of a, not nested under it). + #expect(engine.tokens.map(\.type) == [ + .blockSequenceStart, + .blockMappingStart, + .blockEnd, + .blockEnd, + ]) + } + + @Test("a more-indented value opens a nested mapping") + func test_moreIndentedValueNests() { + // `a:` then ` b: c`: the value is more indented, so it nests. + var engine = PureYAML.Parsing.LibYAML.IndentEngine() + engine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: mark) + engine.unrollIndent(column: 2, mark: mark) + engine.rollIndent(column: 2, number: -1, type: .blockMappingStart, mark: mark) + engine.unrollIndent(column: -1, mark: mark) + + #expect(engine.tokens.map(\.type) == [ + .blockMappingStart, + .blockMappingStart, + .blockEnd, + .blockEnd, + ]) + } + + @Test("flow level makes indentation inert") + func test_flowLevelIsInert() { + var engine = PureYAML.Parsing.LibYAML.IndentEngine() + engine.flowLevel = 1 + engine.rollIndent(column: 4, number: -1, type: .blockMappingStart, mark: mark) + engine.unrollIndent(column: 0, mark: mark) + #expect(engine.tokens.isEmpty) + #expect(engine.indent == -1) + } +} diff --git a/Tests/LibYAMLParserTests.swift b/Tests/LibYAMLParserTests.swift new file mode 100644 index 0000000..87bb659 --- /dev/null +++ b/Tests/LibYAMLParserTests.swift @@ -0,0 +1,158 @@ +@testable import PureYAML +import Testing + +/// End-to-end event production through the ported parser state machine. Events are +/// rendered to the YAML test-suite "yeast" format (mark-independent) so the +/// expectations read like the canonical `test.event` files. +@Suite("LibYAML Parser") +struct LibYAMLParserTests { + private func events(_ input: String) throws -> [String] { + var parser = try PureYAML.Parsing.LibYAML.Parser(input) + return try parser.parse().map(render) + } + + private func render(_ event: PureYAML.Parsing.Event) -> String { + switch event { + case .streamStart: + "+STR" + case .streamEnd: + "-STR" + case let .documentStart(explicit, _): + explicit ? "+DOC ---" : "+DOC" + case let .documentEnd(explicit, _): + explicit ? "-DOC ..." : "-DOC" + case let .sequenceStart(anchor, tag, style, _): + "+SEQ" + (style == .flow ? " []" : "") + properties(anchor, tag) + case .sequenceEnd: + "-SEQ" + case let .mappingStart(anchor, tag, style, _): + "+MAP" + (style == .flow ? " {}" : "") + properties(anchor, tag) + case .mappingEnd: + "-MAP" + case let .scalar(value, anchor, tag, style, _, _): + "=VAL" + properties(anchor, tag) + " " + styleChar(style) + escape(value) + case let .alias(anchor, _): + "=ALI *" + anchor + } + } + + private func properties(_ anchor: String?, _ tag: String?) -> String { + (anchor.map { " &" + $0 } ?? "") + (tag.map { " <" + $0 + ">" } ?? "") + } + + private func styleChar(_ style: PureYAML.Parsing.ScalarStyle) -> String { + switch style { + case .plain: ":" + case .singleQuoted: "'" + case .doubleQuoted: "\"" + case .literal: "|" + case .folded: ">" + } + } + + private func escape(_ value: String) -> String { + var output = "" + for scalar in value.unicodeScalars { + switch scalar { + case "\\": output += "\\\\" + case "\n": output += "\\n" + case "\t": output += "\\t" + case "\r": output += "\\r" + default: output.unicodeScalars.append(scalar) + } + } + return output + } + + @Test("a bare root scalar") + func test_rootScalar() throws { + #expect(try events("x\n") == ["+STR", "+DOC", "=VAL :x", "-DOC", "-STR"]) + } + + @Test("a block sequence") + func test_blockSequence() throws { + #expect(try events("- a\n- b\n") == [ + "+STR", "+DOC", "+SEQ", "=VAL :a", "=VAL :b", "-SEQ", "-DOC", "-STR", + ]) + } + + @Test("a block mapping") + func test_blockMapping() throws { + #expect(try events("a: b\n") == [ + "+STR", "+DOC", "+MAP", "=VAL :a", "=VAL :b", "-MAP", "-DOC", "-STR", + ]) + } + + @Test("a mapping nested in a sequence entry with an empty value") + func test_nestedMappingEmptyValue() throws { + // The original block-mapping bug: `- a:` / ` b: c` is {a: null, b: c}. + #expect(try events("- a:\n b: c\n") == [ + "+STR", "+DOC", "+SEQ", "+MAP", + "=VAL :a", "=VAL :", + "=VAL :b", "=VAL :c", + "-MAP", "-SEQ", "-DOC", "-STR", + ]) + } + + @Test("a flow sequence") + func test_flowSequence() throws { + #expect(try events("[a, b]\n") == [ + "+STR", "+DOC", "+SEQ []", "=VAL :a", "=VAL :b", "-SEQ", "-DOC", "-STR", + ]) + } + + @Test("a flow mapping") + func test_flowMapping() throws { + #expect(try events("{a: b}\n") == [ + "+STR", "+DOC", "+MAP {}", "=VAL :a", "=VAL :b", "-MAP", "-DOC", "-STR", + ]) + } + + @Test("an anchor and an alias") + func test_anchorAlias() throws { + #expect(try events("a: &x 1\nb: *x\n") == [ + "+STR", "+DOC", "+MAP", + "=VAL :a", "=VAL &x :1", + "=VAL :b", "=ALI *x", + "-MAP", "-DOC", "-STR", + ]) + } + + @Test("a shorthand tag resolves against the default !! handle") + func test_shorthandTag() throws { + #expect(try events("!!str x\n") == [ + "+STR", "+DOC", "=VAL :x", "-DOC", "-STR", + ]) + } + + @Test("a custom %TAG directive resolves a shorthand") + func test_tagDirective() throws { + #expect(try events("%TAG !e! tag:example.com,2000:\n---\n!e!foo x\n") == [ + "+STR", "+DOC ---", "=VAL :x", "-DOC", "-STR", + ]) + } + + @Test("a version directive opens an explicit document") + func test_versionDirective() throws { + #expect(try events("%YAML 1.2\n---\nx\n") == [ + "+STR", "+DOC ---", "=VAL :x", "-DOC", "-STR", + ]) + } + + @Test("multiple explicit documents") + func test_multipleDocuments() throws { + #expect(try events("---\na\n---\nb\n") == [ + "+STR", + "+DOC ---", "=VAL :a", "-DOC", + "+DOC ---", "=VAL :b", "-DOC", + "-STR", + ]) + } + + @Test("a quoted scalar is not plain-implicit") + func test_quotedScalar() throws { + #expect(try events("\"x\"\n") == [ + "+STR", "+DOC", "=VAL \"x", "-DOC", "-STR", + ]) + } +} diff --git a/Tests/LibYAMLPortConformanceTests.swift b/Tests/LibYAMLPortConformanceTests.swift new file mode 100644 index 0000000..685b7c8 --- /dev/null +++ b/Tests/LibYAMLPortConformanceTests.swift @@ -0,0 +1,66 @@ +import Foundation +@testable import PureYAML +import Testing + +/// Differential measurement of the ported libyaml scanner+parser against the full +/// vendored YAML test suite, using the same yeast serializer as the canonical +/// gate. Gated by an environment flag so it only runs when measuring; it prints a +/// score and the failing ids split into throws vs wrong-stream. +@Suite("LibYAML Port Conformance") +struct LibYAMLPortConformanceTests { + @Test("measure the ported pipeline against the suite") + func test_measure() throws { + guard ProcessInfo.processInfo.environment["PUREYAML_PORT_MEASURE"] == "1" else { return } + var pass = 0 + var throwing: [String] = [] + var wrong: [String] = [] + let cases = CanonicalEventCorpus.validCases() + for testCase in cases { + guard let yaml = testCase.input, let expected = testCase.expectedEvents else { continue } + do { + var parser = try PureYAML.Parsing.LibYAML.Parser(yaml) + let actual = try parser.parse().map(CanonicalEventCorpus.serialize).joined(separator: "\n") + if actual == expected.trimmedTrailing { + pass += 1 + } else { + wrong.append(testCase.id) + } + } catch { + throwing.append(testCase.id) + } + } + print("PORT-SCORE pass=\(pass) wrong=\(wrong.count) throws=\(throwing.count) total=\(cases.count)") + print("PORT-WRONG \(wrong.sorted().joined(separator: " "))") + print("PORT-THROWS \(throwing.sorted().joined(separator: " "))") + } + + @Test("dump port yeast for ids in PUREYAML_PORT_DUMP_IDS") + func test_dump() throws { + guard let ids = ProcessInfo.processInfo.environment["PUREYAML_PORT_DUMP_IDS"] else { return } + let cases = ids == "ALL" + ? CanonicalEventCorpus.validCases().map(\.id) + : ids.split(separator: ",").map(String.init) + for id in cases { + let testCase = CanonicalEventCorpus.Case(id: id) + guard let yaml = testCase.input else { continue } + print("@@@ID@@@ \(id)") + do { + var parser = try PureYAML.Parsing.LibYAML.Parser(yaml) + try print(parser.parse().map(CanonicalEventCorpus.serialize).joined(separator: "\n")) + } catch { + print("@@@ERROR@@@ \(error)") + } + print("@@@END@@@") + } + } +} + +private extension String { + var trimmedTrailing: String { + var copy = self + while copy.hasSuffix("\n") { + copy.removeLast() + } + return copy + } +} diff --git a/Tests/LibYAMLReaderTests.swift b/Tests/LibYAMLReaderTests.swift new file mode 100644 index 0000000..1ac8f50 --- /dev/null +++ b/Tests/LibYAMLReaderTests.swift @@ -0,0 +1,46 @@ +@testable import PureYAML +import Testing + +/// Verifies the ported reader iterates Unicode scalars with libyaml's mark and +/// `SKIP` / `SKIP_LINE` semantics: CR and LF are distinct scalars, a CR+LF pair +/// is one line break, and the column is 0-based. +@Suite("LibYAML Reader") +struct LibYAMLReaderTests { + @Test("peek and skip advance the column scalar by scalar") + func test_peekAndSkip() { + var reader = PureYAML.Parsing.LibYAML.Reader("ab") + #expect(reader.peek() == "a") + #expect(reader.peek(1) == "b") + #expect(reader.peek(2) == nil) + reader.skip() + #expect(reader.peek() == "b") + #expect(reader.column == 1) + #expect(reader.line == 0) + reader.skip() + #expect(reader.isAtEnd) + #expect(reader.peek() == nil) + } + + @Test("skipLine starts a new line and resets the column") + func test_skipLineLF() { + var reader = PureYAML.Parsing.LibYAML.Reader("a\nb") + reader.skip() + reader.skipLine() + #expect(reader.line == 1) + #expect(reader.column == 0) + #expect(reader.peek() == "b") + } + + @Test("a CR+LF pair is a single line break") + func test_skipLineCRLF() { + var reader = PureYAML.Parsing.LibYAML.Reader("a\r\nb") + reader.skip() + // CR and LF are distinct scalars but one break. + #expect(reader.peek() == "\r") + #expect(reader.peek(1) == "\n") + reader.skipLine() + #expect(reader.line == 1) + #expect(reader.column == 0) + #expect(reader.peek() == "b") + } +} diff --git a/Tests/LibYAMLScannerFetchTests.swift b/Tests/LibYAMLScannerFetchTests.swift new file mode 100644 index 0000000..7e2ed26 --- /dev/null +++ b/Tests/LibYAMLScannerFetchTests.swift @@ -0,0 +1,264 @@ +@testable import PureYAML +import Testing + +/// End-to-end tokenization through the ported fetch loop. The headline case is +/// the original block-mapping bug: `- a:` followed by a same-column `b:` must +/// tokenize as siblings (one BLOCK-MAPPING-START), matching libyaml, while a +/// more-indented value nests (two BLOCK-MAPPING-STARTs). +@Suite("LibYAML Scanner Fetch") +struct LibYAMLScannerFetchTests { + private typealias TokenType = PureYAML.Parsing.LibYAML.TokenType + + private func tokenize(_ input: String) throws -> [TokenType] { + var scanner = PureYAML.Parsing.LibYAML.Scanner(input) + return try scanner.scanAll().map(\.type) + } + + @Test("a block mapping inside a sequence entry keeps same-column keys siblings") + func test_sequenceEntryMappingSiblings() throws { + // The original bug: `- a:` / ` b: c` is one mapping {a: null, b: c}. + let tokens = try tokenize("- a:\n b: c\n") + #expect(tokens == [ + .streamStart, + .blockSequenceStart, + .blockEntry, + .blockMappingStart, + .key, + .scalar(value: "a", style: .plain), + .value, + .key, + .scalar(value: "b", style: .plain), + .value, + .scalar(value: "c", style: .plain), + .blockEnd, + .blockEnd, + .streamEnd, + ]) + } + + @Test("a more-indented value nests a second mapping") + func test_moreIndentedValueNests() throws { + let tokens = try tokenize("a:\n b: c\n") + #expect(tokens == [ + .streamStart, + .blockMappingStart, + .key, + .scalar(value: "a", style: .plain), + .value, + .blockMappingStart, + .key, + .scalar(value: "b", style: .plain), + .value, + .scalar(value: "c", style: .plain), + .blockEnd, + .blockEnd, + .streamEnd, + ]) + } + + @Test("a simple block mapping pair") + func test_simplePair() throws { + let tokens = try tokenize("key: value\n") + #expect(tokens == [ + .streamStart, + .blockMappingStart, + .key, + .scalar(value: "key", style: .plain), + .value, + .scalar(value: "value", style: .plain), + .blockEnd, + .streamEnd, + ]) + } + + @Test("a multi-line plain scalar folds its line break to a space") + func test_plainScalarFolding() throws { + let tokens = try tokenize("a\nb\n") + #expect(tokens == [ + .streamStart, + .scalar(value: "a b", style: .plain), + .streamEnd, + ]) + } + + @Test("a flow sequence of plain scalars") + func test_flowSequence() throws { + let tokens = try tokenize("[a, b]\n") + #expect(tokens == [ + .streamStart, + .flowSequenceStart, + .scalar(value: "a", style: .plain), + .flowEntry, + .scalar(value: "b", style: .plain), + .flowSequenceEnd, + .streamEnd, + ]) + } + + @Test("a flow mapping with a key and value") + func test_flowMapping() throws { + let tokens = try tokenize("{k: v}\n") + #expect(tokens == [ + .streamStart, + .flowMappingStart, + .key, + .scalar(value: "k", style: .plain), + .value, + .scalar(value: "v", style: .plain), + .flowMappingEnd, + .streamEnd, + ]) + } + + @Test("single-quoted scalar with an escaped quote") + func test_singleQuoted() throws { + let tokens = try tokenize("'it''s here'\n") + #expect(tokens == [ + .streamStart, + .scalar(value: "it's here", style: .singleQuoted), + .streamEnd, + ]) + } + + @Test("double-quoted scalar decodes escapes") + func test_doubleQuotedEscapes() throws { + let tokens = try tokenize("\"a\\nb\\tc\\u263A\"\n") + #expect(tokens == [ + .streamStart, + .scalar(value: "a\nb\tc\u{263A}", style: .doubleQuoted), + .streamEnd, + ]) + } + + @Test("a multi-line quoted scalar folds line breaks") + func test_quotedFolding() throws { + let tokens = try tokenize("\"a\nb\"\n") + #expect(tokens == [ + .streamStart, + .scalar(value: "a b", style: .doubleQuoted), + .streamEnd, + ]) + } + + @Test("an anchored scalar value and an alias") + func test_anchorAndAlias() throws { + let tokens = try tokenize("a: &x 1\nb: *x\n") + #expect(tokens == [ + .streamStart, + .blockMappingStart, + .key, + .scalar(value: "a", style: .plain), + .value, + .anchor(name: "x"), + .scalar(value: "1", style: .plain), + .key, + .scalar(value: "b", style: .plain), + .value, + .alias(name: "x"), + .blockEnd, + .streamEnd, + ]) + } + + @Test("a literal block scalar keeps line breaks and clips the trailing newline") + func test_literalBlockScalar() throws { + let tokens = try tokenize("key: |\n a\n b\n") + #expect(tokens == [ + .streamStart, + .blockMappingStart, + .key, + .scalar(value: "key", style: .plain), + .value, + .scalar(value: "a\nb\n", style: .literal), + .blockEnd, + .streamEnd, + ]) + } + + @Test("a folded block scalar joins lines with a space") + func test_foldedBlockScalar() throws { + let tokens = try tokenize("key: >\n a\n b\n") + #expect(tokens == [ + .streamStart, + .blockMappingStart, + .key, + .scalar(value: "key", style: .plain), + .value, + .scalar(value: "a b\n", style: .folded), + .blockEnd, + .streamEnd, + ]) + } + + @Test("a strip chomping indicator drops the trailing newline") + func test_literalStripChomping() throws { + let tokens = try tokenize("key: |-\n a\n") + #expect(tokens == [ + .streamStart, + .blockMappingStart, + .key, + .scalar(value: "key", style: .plain), + .value, + .scalar(value: "a", style: .literal), + .blockEnd, + .streamEnd, + ]) + } + + @Test("a secondary-handle shorthand tag") + func test_shorthandTag() throws { + let tokens = try tokenize("!!str x\n") + #expect(tokens == [ + .streamStart, + .tag(handle: "!!", suffix: "str"), + .scalar(value: "x", style: .plain), + .streamEnd, + ]) + } + + @Test("a local tag uses the primary handle") + func test_localTag() throws { + let tokens = try tokenize("!local x\n") + #expect(tokens == [ + .streamStart, + .tag(handle: "!", suffix: "local"), + .scalar(value: "x", style: .plain), + .streamEnd, + ]) + } + + @Test("a verbatim tag has an empty handle") + func test_verbatimTag() throws { + let tokens = try tokenize("! x\n") + #expect(tokens == [ + .streamStart, + .tag(handle: "", suffix: "tag:yaml.org,2002:str"), + .scalar(value: "x", style: .plain), + .streamEnd, + ]) + } + + @Test("a YAML version directive") + func test_versionDirective() throws { + let tokens = try tokenize("%YAML 1.2\n---\nx\n") + #expect(tokens == [ + .streamStart, + .versionDirective(major: 1, minor: 2), + .documentStart, + .scalar(value: "x", style: .plain), + .streamEnd, + ]) + } + + @Test("a TAG directive maps a handle to a prefix") + func test_tagDirective() throws { + let tokens = try tokenize("%TAG !e! tag:example.com,2000:\n---\nx\n") + #expect(tokens == [ + .streamStart, + .tagDirective(handle: "!e!", prefix: "tag:example.com,2000:"), + .documentStart, + .scalar(value: "x", style: .plain), + .streamEnd, + ]) + } +} diff --git a/Tests/LibYAMLSimpleKeyTests.swift b/Tests/LibYAMLSimpleKeyTests.swift new file mode 100644 index 0000000..33e124d --- /dev/null +++ b/Tests/LibYAMLSimpleKeyTests.swift @@ -0,0 +1,67 @@ +@testable import PureYAML +import Testing + +/// Verifies the ported simple-key mechanism (`save_simple_key`, +/// `remove_simple_key`, `stale_simple_keys`, flow-level push/pop) reproduces +/// libyaml's behavior. +@Suite("LibYAML Simple Key") +struct LibYAMLSimpleKeyTests { + private func mark(line: Int, column: Int, index: Int) -> PureYAML.Parsing.Mark { + PureYAML.Parsing.Mark(line: line, column: column, index: index) + } + + @Test("saves a possible key, required when it sits at the block indent") + func test_saveSimpleKeyRequiredAtIndent() throws { + var scanner = PureYAML.Parsing.LibYAML.Scanner() + scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start) + scanner.mark = mark(line: 1, column: 0, index: 0) + try scanner.saveSimpleKey() + #expect(scanner.simpleKeys.last?.possible == true) + #expect(scanner.simpleKeys.last?.required == true) + } + + @Test("a key not at the block indent is possible but not required") + func test_saveSimpleKeyNotRequired() throws { + var scanner = PureYAML.Parsing.LibYAML.Scanner() + scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start) + scanner.mark = mark(line: 1, column: 4, index: 4) + try scanner.saveSimpleKey() + #expect(scanner.simpleKeys.last?.possible == true) + #expect(scanner.simpleKeys.last?.required == false) + } + + @Test("removing a required possible key is an error") + func test_removeRequiredKeyThrows() throws { + var scanner = PureYAML.Parsing.LibYAML.Scanner() + scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start) + scanner.mark = mark(line: 1, column: 0, index: 0) + try scanner.saveSimpleKey() + #expect(throws: PureYAML.Parsing.LibYAML.ScannerError.self) { + try scanner.removeSimpleKey() + } + } + + @Test("a non-required key on an earlier line goes stale without error") + func test_staleNonRequiredKey() throws { + var scanner = PureYAML.Parsing.LibYAML.Scanner() + scanner.indentEngine.rollIndent(column: 0, number: -1, type: .blockMappingStart, mark: .start) + scanner.mark = mark(line: 1, column: 4, index: 4) + try scanner.saveSimpleKey() + scanner.mark = mark(line: 2, column: 0, index: 10) + try scanner.staleSimpleKeys() + #expect(scanner.simpleKeys.last?.possible == false) + } + + @Test("flow level pushes and pops a simple-key slot") + func test_flowLevelStack() { + var scanner = PureYAML.Parsing.LibYAML.Scanner() + #expect(scanner.simpleKeys.count == 1) + scanner.increaseFlowLevel(isSequence: true) + #expect(scanner.flowLevel == 1) + #expect(scanner.simpleKeys.count == 2) + #expect(scanner.flowIsSequence == [true]) + scanner.decreaseFlowLevel() + #expect(scanner.flowLevel == 0) + #expect(scanner.simpleKeys.count == 1) + } +} diff --git a/Tests/LocatedValueConformanceTests.swift b/Tests/LocatedValueConformanceTests.swift index f0e45ef..ab580f0 100644 --- a/Tests/LocatedValueConformanceTests.swift +++ b/Tests/LocatedValueConformanceTests.swift @@ -65,36 +65,20 @@ struct LocatedValueConformanceTests { #expect(items[0].value == .string("first")) } - /// Every case in the official suite that parses cleanly must have a located projection - /// identical to its plain parse, so the located tree shape never drifts from the value tree. - /// Opt-in like the plain conformance harness: set `PUREYAML_RUN_YAML_TEST_SUITE=1` and point - /// `PUREYAML_YAML_TEST_SUITE_DIR` at a checkout of the suite's case directories. @Test("Every passing suite case projects to the same value as a plain parse") func test_locatedMatchesPlainParseAcrossSuite() throws { guard ProcessInfo.processInfo.environment["PUREYAML_RUN_YAML_TEST_SUITE"] == "1" else { return } - let manager = FileManager.default - let root = ProcessInfo.processInfo.environment["PUREYAML_YAML_TEST_SUITE_DIR"] - ?? manager.currentDirectoryPath + "/.build/yaml-test-suite" - let names = try #require(try? manager.contentsOfDirectory(atPath: root), "suite corpus not found at \(root)") - var compared = 0 - for name in names.sorted() { - let dir = root + "/" + name - guard manager.fileExists(atPath: dir + "/in.yaml"), - !manager.fileExists(atPath: dir + "/error"), - let yaml = try? String(contentsOfFile: dir + "/in.yaml", encoding: .utf8) - else { - continue - } - // Only compare cases that parse cleanly; the located projection must match exactly. + let manifest = try YAMLTestSuiteManifest.load() + for testCase in manifest.cases where testCase.expected == "parse-ok" && testCase.status == "passing" { + let yaml = try testCase.loadInput() + // A passing parse-ok case parses cleanly; the located projection must match exactly. guard let plain = try? PureYAML.parseStream(yaml).map(\.value) else { continue } let located = try PureYAML.parseStreamLocated(yaml).map(\.value) - #expect(located == plain, "\(name): located projection diverged from plain parse") - compared += 1 + #expect(located == plain, "\(testCase.id) \"\(testCase.name)\": located projection diverged from plain parse") } - #expect(compared > 0) } } diff --git a/Tests/MultilineImplicitKeyTests.swift b/Tests/MultilineImplicitKeyTests.swift index 3db8943..71ec297 100644 --- a/Tests/MultilineImplicitKeyTests.swift +++ b/Tests/MultilineImplicitKeyTests.swift @@ -15,10 +15,10 @@ struct MultilineImplicitKeyTests { @Test("Single-line keys, multiline values, flow keys, and explicit keys stay valid", arguments: [ "\"a b\": 1\n", // a single-line quoted key - "k: \"a\nb\"\n", // a multiline quoted value (not a key) + "k: \"a\n b\"\n", // a multiline quoted value (not a key), continuation indented "{ \"a\nb\": 1 }\n", // a flow mapping key may span lines "---\n- { \"multi\n line\": value}\n", // a multiline flow key inside a sequence - "? \"a\nb\"\n: v\n", // an explicit key may span lines + "? \"a\n b\"\n: v\n", // an explicit key may span lines, continuation indented ]) func test_validQuotedKeysAndValues(_ yaml: String) throws { _ = try PureYAML.parse(yaml) diff --git a/Tests/ParsingBlockScalarIndicatorTests.swift b/Tests/ParsingBlockScalarIndicatorTests.swift new file mode 100644 index 0000000..31469ed --- /dev/null +++ b/Tests/ParsingBlockScalarIndicatorTests.swift @@ -0,0 +1,70 @@ +@testable import PureYAML +import Testing + +@Suite("Parsing Block Scalar Indicators") +struct ParsingBlockScalarIndicatorTests { + @Test("Parses block scalar text that starts with YAML indicators") + func test_blockScalarTextThatStartsWithYAMLIndicators() throws { + let root = try requireMapping(PureYAML.parse( + """ + description: | + **Fine-grained access tokens** + + * [GitHub App user access tokens](https://docs.github.com) + - dash list item stays text + """, + )) + + // A literal block scalar preserves the blank line between the heading and + // the list (YAML 1.2 line 8.1.1.1); clip keeps a single trailing newline. + #expect(root?["description"] == .string( + """ + **Fine-grained access tokens** + + * [GitHub App user access tokens](https://docs.github.com) + - dash list item stays text + + """, + )) + } + + @Test("Block scalars keep a leading '#' as literal content, not a comment") + func test_blockScalarLeadingHashIsLiteralContent() throws { + let root = try requireMapping(PureYAML.parse( + """ + folded: + $ref: >- + #/components/schemas/foo + literal: + $ref: |- + #/components/schemas/bar + """, + )) + + #expect(root?.mapping("folded")?["$ref"] == .string("#/components/schemas/foo")) + #expect(root?.mapping("literal")?["$ref"] == .string("#/components/schemas/bar")) + } + + @Test("A leading '#' is preserved across every line of a block scalar") + func test_blockScalarLeadingHashAcrossMultipleLines() throws { + let root = try requireMapping(PureYAML.parse( + """ + doc: |- + #/components/schemas/foo + plain line + #/components/schemas/bar + after: tail + """, + )) + + #expect(root?["doc"] == .string( + """ + #/components/schemas/foo + plain line + #/components/schemas/bar + """, + )) + // The block scalar ends at the dedent; the following key is unaffected. + #expect(root?["after"] == .string("tail")) + } +} diff --git a/Tests/ParsingErrorPathTests.swift b/Tests/ParsingErrorPathTests.swift index 00c7368..1dd5597 100644 --- a/Tests/ParsingErrorPathTests.swift +++ b/Tests/ParsingErrorPathTests.swift @@ -16,17 +16,20 @@ struct ParsingErrorPathTests { @Test("An unterminated flow mapping throws at stream end") func test_unterminatedFlowMappingThrows() { - expectParseError("x: {a: b", .unexpectedToken( - expected: "flow entry or flow mapping end", - actual: "streamEnd", + expectParseError("x: {a: b", .malformed( + reason: "while parsing a flow mapping, did not find expected ',' or '}'", line: 1, - column: 9, + column: 4, )) } @Test("Block scalar content less indented than the explicit indicator throws") func test_explicitBlockScalarIndentationUnderIndentThrows() { - expectParseError("k: |2\n a\n", .unexpectedIndentation(line: 2)) + expectParseError("k: |2\n a\n", .malformed( + reason: "while parsing a block mapping, did not find expected key", + line: 1, + column: 1, + )) } @Test("Diagnostic validation reports an invalid merge value via the buffered composer") diff --git a/Tests/ParsingErrorTests.swift b/Tests/ParsingErrorTests.swift index 6c00953..16a8c57 100644 --- a/Tests/ParsingErrorTests.swift +++ b/Tests/ParsingErrorTests.swift @@ -5,12 +5,19 @@ import Testing struct ParsingErrorTests { @Test("Reports exact parser errors") func test_errorReporting() { - expectParseError("root:\n child: yes\n wrong: no", .unexpectedIndentation(line: 3)) - expectParseError("- one\nkey: value", .mixedCollectionStyles(line: 2)) - expectParseError("root:\n child: value\n dangling", .unexpectedToken( - expected: "mapping key", - actual: "scalar value=\"dangling\" style=plain", - line: 3, + expectParseError("root:\n child: yes\n wrong: no", .malformed( + reason: "while parsing a block mapping, did not find expected key", + line: 1, + column: 1, + )) + expectParseError("- one\nkey: value", .malformed( + reason: "while parsing a block collection, did not find expected '-' indicator", + line: 1, + column: 1, + )) + expectParseError("root:\n child: value\n dangling", .malformed( + reason: "while parsing a block mapping, did not find expected key", + line: 2, column: 3, )) expectParseError("name: \"open", .unterminatedQuotedString(line: 1)) @@ -32,16 +39,20 @@ struct ParsingErrorTests { #expect(try PureYAML.parse(" \n# comment only\n") == .null) } - @Test("Parses tab indentation with permissive tab stops") - func test_tabIndentationUsesPermissiveTabStops() throws { - let root = try requireMapping(PureYAML.parse( - """ - root: - \tchild: value - """, - )) - - #expect(root?.mapping("root")?["child"] == .string("value")) + @Test("Rejects a tab used as block indentation") + func test_tabIndentationIsRejected() { + // YAML 1.2 forbids a tab from supplying block-structure indentation + // (spec rule s-indent is spaces only; libyaml scanner.c:1948-1953 refuses + // to consume a tab as whitespace where a simple key is allowed). The nested + // `child` mapping is indented by a tab, so the document must be rejected. + #expect(throws: PureYAML.Parsing.ParseError.self) { + try PureYAML.parse( + """ + root: + \tchild: value + """, + ) + } } @Test("Parser errors describe returned failures") @@ -53,6 +64,7 @@ struct ParsingErrorTests { #expect(PureYAML.Parsing.ParseError.unterminatedTag(line: 8).description == "unterminated tag at line 8") #expect(PureYAML.Parsing.ParseError.unterminatedQuotedString(line: 9).description == "unterminated quoted string at line 9") #expect(PureYAML.Parsing.ParseError.incompatibleYAMLDirective(line: 10).description == "incompatible YAML directive at line 10") + #expect(PureYAML.Parsing.ParseError.directiveWithoutDocument(line: 10).description == "directive is not followed by a document start at line 10") #expect(PureYAML.Parsing.ParseError.unsupportedDirective(name: "%FOO", line: 10).description == "unsupported directive '%FOO' at line 10") #expect(PureYAML.Parsing.ParseError.unsupportedMultiDocumentStream(line: 10).description == "multi-document streams are not supported at line 10") #expect(PureYAML.Parsing.ParseError.expectedNode(line: 10, column: 2).description == "expected a YAML node at line 10, column 2") diff --git a/Tests/ParsingEventTests.swift b/Tests/ParsingEventTests.swift index 8de7ce9..6d7c7b9 100644 --- a/Tests/ParsingEventTests.swift +++ b/Tests/ParsingEventTests.swift @@ -31,7 +31,7 @@ struct ParsingEventTests { #expect(events.map(\.description) == [ "streamStart @1:1@0", - "documentStart @1:1@0", + "documentStart explicit=false @1:1@0", "mappingStart anchor=- tag=- style=block @1:1@0", "scalar value=\"name\" anchor=- tag=- style=plain @1:1@0", "scalar value=\"Example\" anchor=- tag=- style=doubleQuoted @1:7@6", @@ -39,9 +39,9 @@ struct ParsingEventTests { "scalar value=\"it's\" anchor=- tag=- style=singleQuoted @2:9@24", "scalar value=\"missing\" anchor=- tag=- style=plain @3:1@32", "scalar value=\"\" anchor=- tag=- style=plain @3:9@40", - "mappingEnd @3:9@40", - "documentEnd @3:9@40", - "streamEnd @3:9@40", + "mappingEnd @4:1@40", + "documentEnd explicit=false @4:1@40", + "streamEnd @4:1@40", ]) } @@ -57,7 +57,7 @@ struct ParsingEventTests { #expect(events.map(\.description) == [ "streamStart @1:1@0", - "documentStart @1:1@0", + "documentStart explicit=false @1:1@0", "mappingStart anchor=- tag=- style=block @1:1@0", "scalar value=\"servers\" anchor=- tag=- style=plain @1:1@0", "sequenceStart anchor=- tag=- style=block @2:3@11", @@ -66,11 +66,11 @@ struct ParsingEventTests { "scalar value=\"/\" anchor=- tag=- style=plain @2:10@18", "scalar value=\"description\" anchor=- tag=- style=plain @3:5@24", "scalar value=\"Default\" anchor=- tag=- style=plain @3:18@37", - "mappingEnd @3:25@44", - "sequenceEnd @3:25@44", - "mappingEnd @3:25@44", - "documentEnd @3:25@44", - "streamEnd @3:25@44", + "mappingEnd @4:1@44", + "sequenceEnd @4:1@44", + "mappingEnd @4:1@44", + "documentEnd explicit=false @4:1@44", + "streamEnd @4:1@44", ]) #expect(!events.map(\.description).contains("scalar value=\"\" anchor=- tag=- style=plain @1:1@0")) } @@ -86,7 +86,7 @@ struct ParsingEventTests { let descriptions = events.map(\.description) #expect(descriptions == [ "streamStart @1:1@0", - "documentStart @1:1@0", + "documentStart explicit=false @1:1@0", "mappingStart anchor=- tag=- style=block @1:1@0", "scalar value=\"flow\" anchor=- tag=- style=plain @1:1@0", "sequenceStart anchor=- tag=- style=flow @1:7@6", @@ -94,12 +94,12 @@ struct ParsingEventTests { "alias anchor=item @1:30@29", "mappingStart anchor=- tag=- style=flow @1:37@36", "scalar value=\"tagged\" anchor=- tag=- style=plain @1:38@37", - "scalar value=\"it's\" anchor=- tag=! style=singleQuoted @1:46@45", - "mappingEnd @1:84@83", - "sequenceEnd @1:85@84", - "mappingEnd @1:85@84", - "documentEnd @1:85@84", - "streamEnd @1:85@84", + "scalar value=\"it's\" anchor=- tag=tag:example.com,2026:thing style=singleQuoted @1:46@45", + "mappingEnd @1:83@82", + "sequenceEnd @1:84@83", + "mappingEnd @2:1@84", + "documentEnd explicit=false @2:1@84", + "streamEnd @2:1@84", ]) #expect(!descriptions.contains("sequenceStart anchor=- tag=- style=block @1:7@6")) #expect(!descriptions.contains { $0.contains("it''s") }) @@ -150,7 +150,7 @@ struct ParsingEventTests { let descriptions = events.map(\.description) #expect(descriptions == [ "streamStart @1:1@0", - "documentStart @1:1@0", + "documentStart explicit=false @1:1@0", "mappingStart anchor=- tag=- style=block @1:1@0", "scalar value=\"text\" anchor=- tag=- style=plain @1:1@0", "scalar value=\"one\\ntwo\\n\" anchor=- tag=- style=literal @1:7@6", @@ -158,35 +158,37 @@ struct ParsingEventTests { "scalar value=\"one\\ntwo\" anchor=- tag=- style=literal @4:11@30", "scalar value=\"folded\" anchor=- tag=- style=plain @7:1@45", "scalar value=\"one two\\n\" anchor=- tag=- style=folded @7:9@53", - "mappingEnd @9:6@66", - "documentEnd @9:6@66", - "streamEnd @9:6@66", + "mappingEnd @10:1@66", + "documentEnd explicit=false @10:1@66", + "streamEnd @10:1@66", ]) #expect(!descriptions.contains { $0.contains("one\\ntwo\\n") && $0.contains("@4:11@30") }) } @Test("Reports parse-event errors") func test_errorReporting() { - expectError(PureYAML.Parsing.ParseError.unexpectedIndentation(line: 3)) { + expectError(PureYAML.Parsing.ParseError.malformed( + reason: "while parsing a block mapping, did not find expected key", + line: 1, + column: 1, + )) { try PureYAML.Parsing.Parser().parseEvents("root:\n child: yes\n wrong: no") } - expectError(PureYAML.Parsing.ParseError.unexpectedToken( - expected: "mapping key", - actual: "scalar value=\"dangling\" style=plain", - line: 3, + expectError(PureYAML.Parsing.ParseError.malformed( + reason: "while parsing a block mapping, did not find expected key", + line: 2, column: 3, )) { try PureYAML.Parsing.Parser().parseEvents("root:\n child: value\n dangling") } expectParseEventError( "items: [one, two", - PureYAML.Parsing.ParseError.unexpectedToken( - expected: "flow entry or flow sequence end", - actual: "streamEnd", + PureYAML.Parsing.ParseError.malformed( + reason: "while parsing a flow sequence, did not find expected ',' or ']'", line: 1, - column: 17, + column: 8, ), - description: "expected flow entry or flow sequence end at line 1, column 17, found streamEnd", + description: "while parsing a flow sequence, did not find expected ',' or ']' at line 1, column 8", ) } diff --git a/Tests/ParsingMultilineScalarTests.swift b/Tests/ParsingMultilineScalarTests.swift index 55b2a18..858ff06 100644 --- a/Tests/ParsingMultilineScalarTests.swift +++ b/Tests/ParsingMultilineScalarTests.swift @@ -175,69 +175,31 @@ struct ParsingMultilineScalarTests { #expect(root?.mapping("label")?["missing"] == nil) } - @Test("Parses block scalar text that starts with YAML indicators") - func test_blockScalarTextThatStartsWithYAMLIndicators() throws { - let root = try requireMapping(PureYAML.parse( - """ - description: | - **Fine-grained access tokens** - - * [GitHub App user access tokens](https://docs.github.com) - - dash list item stays text - """, - )) - - // A literal block scalar preserves the blank line between the heading and - // the list (YAML 1.2 line 8.1.1.1); clip keeps a single trailing newline. - #expect(root?["description"] == .string( - """ - **Fine-grained access tokens** - - * [GitHub App user access tokens](https://docs.github.com) - - dash list item stays text - - """, - )) + @Test("A bare multi-line plain scalar at the document root folds") + func test_rootMultilinePlainScalarFolds() throws { + // YAML test suite 9YRD: a plain scalar is the document's root node and spans + // several lines. A single line break folds to a space, a blank line folds to + // a newline, and per-line leading/trailing whitespace is stripped. + #expect(try PureYAML.parse("a\nb \n c\nd\n\ne\n") == .string("a b c d\ne")) + // EX5H: the same content after an explicit `---` document-start marker. + #expect(try PureYAML.parse("---\na\nb \n c\nd\n\ne\n") == .string("a b c d\ne")) + // 82AN: `---word1` is plain content (the `---` is not a marker because it is + // not followed by a space), and the scalar continues onto the next line. + #expect(try PureYAML.parse("---word1\nword2\n") == .string("---word1 word2")) } - @Test("Block scalars keep a leading '#' as literal content, not a comment") - func test_blockScalarLeadingHashIsLiteralContent() throws { + @Test("A multi-line plain scalar as a mapping value at root folds") + func test_rootMappingValueMultilinePlainScalarFolds() throws { + // YAML test suite 4CQQ: the value indented on its own lines folds even though + // each continuation line sits at the same column as the first content line. let root = try requireMapping(PureYAML.parse( """ - folded: - $ref: >- - #/components/schemas/foo - literal: - $ref: |- - #/components/schemas/bar + plain: + This unquoted scalar + spans many lines. """, )) - - #expect(root?.mapping("folded")?["$ref"] == .string("#/components/schemas/foo")) - #expect(root?.mapping("literal")?["$ref"] == .string("#/components/schemas/bar")) - } - - @Test("A leading '#' is preserved across every line of a block scalar") - func test_blockScalarLeadingHashAcrossMultipleLines() throws { - let root = try requireMapping(PureYAML.parse( - """ - doc: |- - #/components/schemas/foo - plain line - #/components/schemas/bar - after: tail - """, - )) - - #expect(root?["doc"] == .string( - """ - #/components/schemas/foo - plain line - #/components/schemas/bar - """, - )) - // The block scalar ends at the dedent; the following key is unaffected. - #expect(root?["after"] == .string("tail")) + #expect(root?["plain"] == .string("This unquoted scalar spans many lines.")) } @Test("A genuine trailing comment after a plain value is still ignored") diff --git a/Tests/PerformancePhaseTests.swift b/Tests/PerformancePhaseTests.swift deleted file mode 100644 index 03bf685..0000000 --- a/Tests/PerformancePhaseTests.swift +++ /dev/null @@ -1,298 +0,0 @@ -import Foundation -@testable import PureYAML -import Testing - -@Suite("Performance Phases") -struct PerformancePhaseTests { - @Test("Profiles parser phases for representative slow corpus seeds") - func test_profilesParserPhasesForRepresentativeSeeds() throws { - guard ProcessInfo.processInfo.environment["PUREYAML_RUN_PHASE_PROFILER"] == "1" else { - return - } - - let measurements = try PerformancePhaseSeed.all.map(profile) - let slowestLazyParse = measurements.map(\.lazyParse.seconds).max() ?? 0 - let slowestMaterializedPipeline = measurements.map(\.materializedPipelineSeconds).max() ?? 0 - let report: [String: Any] = [ - "summary": [ - "seeds": measurements.count, - "slowestLazyParseSeconds": slowestLazyParse, - "slowestMaterializedPipelineSeconds": slowestMaterializedPipeline, - ], - "measurements": measurements.map(\.object), - ] - let artifactURL = try performancePhaseArtifactURL() - let data = try JSONSerialization.data(withJSONObject: report, options: [.prettyPrinted, .sortedKeys]) - try data.write(to: artifactURL) - - print("PureYAML phase profiler seeds: \(measurements.count)") - for measurement in measurements { - print(measurement.summaryLine) - } - print("Report: \(artifactURL.path)") - } -} - -private struct PerformancePhaseSeed { - var id: String - var localPath: String - var iterations: Int - - static let all = [ - PerformancePhaseSeed( - id: "cert-manager-crd", - localPath: "cert-manager-certificate-crd.yaml", - iterations: 20, - ), - PerformancePhaseSeed( - id: "stripe-yaml", - localPath: "api-guru-stripe-openapi.yaml", - iterations: 2, - ), - PerformancePhaseSeed( - id: "zoom-yaml", - localPath: "api-guru-zoom-openapi.yaml", - iterations: 2, - ), - ] -} - -private struct PhaseTiming { - var seconds: TimeInterval - var units: Int - - var object: [String: Any] { - [ - "seconds": seconds, - "units": units, - ] - } -} - -private struct PhaseMeasurement { - var seed: PerformancePhaseSeed - var bytes: Int - var scanner: PhaseTiming - var eventParser: PhaseTiming - var composer: PhaseTiming - var lazyParse: PhaseTiming - var validation: PhaseTiming - var dumping: PhaseTiming - - var materializedPipelineSeconds: TimeInterval { - scanner.seconds + eventParser.seconds + composer.seconds - } - - var object: [String: Any] { - [ - "id": seed.id, - "localPath": seed.localPath, - "bytes": bytes, - "iterations": seed.iterations, - "scanner": scanner.object, - "eventParser": eventParser.object, - "composer": composer.object, - "lazyParse": lazyParse.object, - "validation": validation.object, - "dumping": dumping.object, - "materializedPipelineSeconds": materializedPipelineSeconds, - ] - } - - var summaryLine: String { - [ - seed.id, - "bytes=\(bytes)", - "iter=\(seed.iterations)", - "scan=\(format(scanner.seconds))s", - "events=\(format(eventParser.seconds))s", - "compose=\(format(composer.seconds))s", - "lazy=\(format(lazyParse.seconds))s", - "validate=\(format(validation.seconds))s", - "dump=\(format(dumping.seconds))s", - ].joined(separator: " ") - } -} - -private struct WarmedPerformanceInputs { - var tokens: [PureYAML.Parsing.Token] - var events: [PureYAML.Parsing.Event] - var documents: [PureYAML.Stream.Document] -} - -private func profile(_ seed: PerformancePhaseSeed) throws -> PhaseMeasurement { - let yaml = try String(contentsOf: fixtureURL(for: seed), encoding: .utf8) - let parser = PureYAML.Parsing.Parser() - let warmed = try warmup(yaml: yaml, parser: parser) - let scanner = try timeScanner(yaml: yaml, iterations: seed.iterations) - let eventParser = try timeEventParser(tokens: warmed.tokens, parser: parser, iterations: seed.iterations) - let composer = try timeComposer(events: warmed.events, parser: parser, iterations: seed.iterations) - let lazyParse = try timeLazyParse(yaml: yaml, iterations: seed.iterations) - let validation = timeValidation(documents: warmed.documents, iterations: seed.iterations) - let dumping = timeDumping(documents: warmed.documents, iterations: seed.iterations) - - return PhaseMeasurement( - seed: seed, - bytes: yaml.utf8.count, - scanner: .init(seconds: scanner.seconds, units: scanner.value), - eventParser: .init(seconds: eventParser.seconds, units: eventParser.value), - composer: .init(seconds: composer.seconds, units: composer.value), - lazyParse: .init(seconds: lazyParse.seconds, units: lazyParse.value), - validation: .init(seconds: validation.seconds, units: validation.value), - dumping: .init(seconds: dumping.seconds, units: dumping.value), - ) -} - -private func warmup( - yaml: String, - parser: PureYAML.Parsing.Parser, -) throws -> WarmedPerformanceInputs { - let tokens = try PureYAML.Parsing.Scanner().scan(yaml) - var eventParser = PureYAML.Parsing.TokenEventParser(tokens: tokens, scalarParser: parser) - let events = try eventParser.parse() - var composer = PureYAML.Parsing.EventComposer(events: events, scalarParser: parser) - let documents = try composer.composeStream() - _ = PureYAML.Validation.Validator().collect(documents) - _ = PureYAML.dump(documents) - _ = try PureYAML.parseStream(yaml) - return WarmedPerformanceInputs(tokens: tokens, events: events, documents: documents) -} - -private func timeScanner( - yaml: String, - iterations: Int, -) throws -> (seconds: TimeInterval, value: Int) { - try timed { - var units = 0 - for _ in 0 ..< iterations { - units += try PureYAML.Parsing.Scanner().scan(yaml).count - } - return units - } -} - -private func timeEventParser( - tokens: [PureYAML.Parsing.Token], - parser: PureYAML.Parsing.Parser, - iterations: Int, -) throws -> (seconds: TimeInterval, value: Int) { - try timed { - var units = 0 - for _ in 0 ..< iterations { - var eventParser = PureYAML.Parsing.TokenEventParser(tokens: tokens, scalarParser: parser) - units += try eventParser.parse().count - } - return units - } -} - -private func timeComposer( - events: [PureYAML.Parsing.Event], - parser: PureYAML.Parsing.Parser, - iterations: Int, -) throws -> (seconds: TimeInterval, value: Int) { - try timed { - var units = 0 - for _ in 0 ..< iterations { - var composer = PureYAML.Parsing.EventComposer(events: events, scalarParser: parser) - units += try composer.composeStream().count - } - return units - } -} - -private func timeLazyParse( - yaml: String, - iterations: Int, -) throws -> (seconds: TimeInterval, value: Int) { - try timed { - var units = 0 - for _ in 0 ..< iterations { - units += try PureYAML.parseStream(yaml).count - } - return units - } -} - -private func timeValidation( - documents: [PureYAML.Stream.Document], - iterations: Int, -) -> (seconds: TimeInterval, value: Int) { - timed { - var units = 0 - for _ in 0 ..< iterations { - units += PureYAML.Validation.Validator().collect(documents).issues.count - } - return units - } -} - -private func timeDumping( - documents: [PureYAML.Stream.Document], - iterations: Int, -) -> (seconds: TimeInterval, value: Int) { - timed { - var units = 0 - for _ in 0 ..< iterations { - units += PureYAML.dump(documents).utf8.count - } - return units - } -} - -private func fixtureURL(for seed: PerformancePhaseSeed) throws -> URL { - try #require(Bundle.module.url( - forResource: seed.resourceName, - withExtension: seed.resourceExtension, - subdirectory: "Fixtures/real-yaml", - )) -} - -private func performancePhaseArtifactURL() throws -> URL { - if let path = ProcessInfo.processInfo.environment["PUREYAML_PHASE_PROFILER_ARTIFACT"] { - let url = URL(fileURLWithPath: path) - try FileManager.default.createDirectory( - at: url.deletingLastPathComponent(), - withIntermediateDirectories: true, - ) - return url - } - - let url = URL(fileURLWithPath: FileManager.default.currentDirectoryPath) - .appendingPathComponent(".build") - .appendingPathComponent("pureyaml-artifacts") - .appendingPathComponent("performance") - .appendingPathComponent("phase-profile.json") - try FileManager.default.createDirectory( - at: url.deletingLastPathComponent(), - withIntermediateDirectories: true, - ) - return url -} - -private func timed(_ body: () throws -> Int) rethrows -> (seconds: TimeInterval, value: Int) { - let start = DispatchTime.now().uptimeNanoseconds - let value = try body() - let end = DispatchTime.now().uptimeNanoseconds - return (Double(end - start) / 1_000_000_000, value) -} - -private func format(_ value: Double) -> String { - String(format: "%.3f", value) -} - -private extension PerformancePhaseSeed { - var resourceName: String { - guard let dotIndex = localPath.lastIndex(of: ".") else { - return localPath - } - return String(localPath[.. PureYAML.Model.Value { + .mapping(.init(pairs)) + } + + @Test("mappingKeysAreStrings fails on a complex key") + func test_mappingKeysAreStrings_fails() { + let document = mapping([.init(keyNode: .sequence([.int(1)]), value: .int(2))]) + let issues = PureYAML.Validation.Validator(checks: [PureYAML.Validation.AnyCheck(PureYAML.Validation.BuiltinCheck.mappingKeysAreStrings)]).collect(document).issues + #expect(issues.count == 1) + #expect(issues.first?.reason == "Mapping key '[1]' is not a string") + } + + @Test("mappingKeysAreStrings passes when every key is a string") + func test_mappingKeysAreStrings_passes() { + let document = mapping([.init(key: "a", value: .int(1))]) + let issues = PureYAML.Validation.Validator(checks: [PureYAML.Validation.AnyCheck(PureYAML.Validation.BuiltinCheck.mappingKeysAreStrings)]).collect(document).issues + #expect(issues.isEmpty) + } + + @Test("numbersAreFinite fails on infinity at the value's path") + func test_numbersAreFinite_fails() { + let document = mapping([.init(key: "x", value: .double(.infinity))]) + let issues = PureYAML.Validation.Validator(checks: [PureYAML.Validation.AnyCheck(PureYAML.Validation.BuiltinCheck.numbersAreFinite)]).collect(document).issues + #expect(issues.count == 1) + #expect(issues.first?.reason == "Number 'inf' is not finite") + } + + @Test("numbersAreFinite passes on a large finite double") + func test_numbersAreFinite_passes() { + let document = mapping([.init(key: "x", value: .double(.greatestFiniteMagnitude))]) + let issues = PureYAML.Validation.Validator(checks: [PureYAML.Validation.AnyCheck(PureYAML.Validation.BuiltinCheck.numbersAreFinite)]).collect(document).issues + #expect(issues.isEmpty) + } + + @Test("The representability set catches a duplicate key") + func test_representability_catchesDuplicate() { + let document = mapping([.init(key: "a", value: .int(1)), .init(key: "a", value: .int(2))]) + #expect(!PureYAML.JSON.Validator.isRepresentable(document)) + } + + @Test("A plain string-keyed finite tree is representable") + func test_representability_acceptsPlainTree() { + let document = mapping([.init(key: "a", value: .int(1)), .init(key: "b", value: .double(1.5))]) + #expect(PureYAML.JSON.Validator.isRepresentable(document)) + #expect(PureYAML.JSON.Validator.issues(for: document).isEmpty) + } +} diff --git a/Tests/PureYAMLJSONTests/JSONWriterTests.swift b/Tests/PureYAMLJSONTests/JSONWriterTests.swift new file mode 100644 index 0000000..571bb39 --- /dev/null +++ b/Tests/PureYAMLJSONTests/JSONWriterTests.swift @@ -0,0 +1,50 @@ +import PureYAML +@testable import PureYAMLJSON +import Testing + +@Suite("JSON Writer") +struct JSONWriterTests { + @Test("Emits a compact object on one line") + func test_emitsCompactObject() throws { + let value = try PureYAML.parse("a: 1\nb:\n - true\n - null") + let json = try PureYAML.JSON.Writer.string(from: value, options: .compact) + #expect(json == "{\"a\":1,\"b\":[true,null]}") + } + + @Test("Pretty output indents and survives a round-trip") + func test_emitsPrettyObject() throws { + let value = try PureYAML.parse("a: 1\nb:\n - x") + let json = try PureYAML.JSON.Writer.string(from: value, options: .pretty) + #expect(json.contains("\n")) + #expect(try PureYAML.parse(json) == value) + } + + @Test("Empty containers emit as [] and {}") + func test_emitsEmptyContainers() throws { + let object = try PureYAML.JSON.Writer.string(from: .mapping(.init([])), options: .compact) + let array = try PureYAML.JSON.Writer.string(from: .sequence([]), options: .compact) + #expect(object == "{}") + #expect(array == "[]") + } + + @Test("A non-string mapping key is rejected") + func test_rejectsNonStringKey() { + let value = PureYAML.Model.Value.mapping(.init([.init(keyNode: .sequence([.int(1)]), value: .int(2))])) + #expect(throws: PureYAML.JSON.Writer.Failure.self) { + _ = try PureYAML.JSON.Writer.string(from: value) + } + } + + @Test("A non-finite number is rejected") + func test_rejectsNonFiniteNumber() { + #expect(throws: PureYAML.JSON.Writer.Failure.nonFiniteNumber(.infinity)) { + _ = try PureYAML.JSON.Writer.string(from: .double(.infinity)) + } + } + + @Test("Control characters and quotes are escaped per RFC 8259") + func test_escapesControlCharacters() throws { + let json = try PureYAML.JSON.Writer.string(from: .string("a\"b\\c\n\u{01}"), options: .compact) + #expect(json == "\"a\\\"b\\\\c\\n\\u0001\"") + } +} diff --git a/Tests/ScannerTests.swift b/Tests/ScannerTests.swift deleted file mode 100644 index 2df6d5d..0000000 --- a/Tests/ScannerTests.swift +++ /dev/null @@ -1,393 +0,0 @@ -@testable import PureYAML -import Testing - -@Suite("Scanner") -struct ScannerTests { - @Test("Scans comments indentation block entries and mapping keys") - func test_commentsIndentationBlockEntriesAndMappingKeys() throws { - let tokens = try scanKinds( - """ - # leading - root: - - name: "one" # inline - enabled: true - """, - ) - - expectKinds(tokens, [ - "streamStart", - "comment value=\"leading\"", - "mappingKey", - "scalar value=\"root\" style=plain", - "mappingValue", - "indent width=2", - "blockEntry", - "mappingKey", - "scalar value=\"name\" style=plain", - "mappingValue", - "scalar value=\"one\" style=doubleQuoted", - "comment value=\"inline\"", - "indent width=4", - "mappingKey", - "scalar value=\"enabled\" style=plain", - "mappingValue", - "scalar value=\"true\" style=plain", - "dedent width=2", - "dedent width=0", - "streamEnd", - ]) - expectDoesNotContain(tokens, [ - "flowSequenceStart", - "flowMappingStart", - "tag value=!Thing", - ]) - } - - @Test("Scans explicit mapping keys and lower-indent dedents") - func test_explicitMappingKeysAndLowerIndentDedents() throws { - let tokens = try scanKinds( - """ - root: - nested: - value: yes - ? explicit - : answer - """, - ) - - expectKinds(tokens, [ - "streamStart", - "mappingKey", - "scalar value=\"root\" style=plain", - "mappingValue", - "indent width=2", - "mappingKey", - "scalar value=\"nested\" style=plain", - "mappingValue", - "indent width=4", - "mappingKey", - "scalar value=\"value\" style=plain", - "mappingValue", - "scalar value=\"yes\" style=plain", - "dedent width=2", - "dedent width=0", - "mappingKey", - "scalar value=\"explicit\" style=plain", - "mappingValue", - "scalar value=\"answer\" style=plain", - "streamEnd", - ]) - expectContains(tokens, [ - "dedent width=2", - "dedent width=0", - "mappingKey", - "mappingValue", - ]) - } - - @Test("Scans flow delimiters quoted scalars anchors aliases tags and block scalar headers") - func test_flowDelimitersQuotedScalarsAnchorsAliasesTagsAndBlockScalarHeaders() throws { - let tokens = try scanKinds( - """ - flow: [!Thing &item "value", *item, {tagged: ! 'it''s'}] - text: |+ - line - folded: >- - line - """, - ) - - expectFlowAndBlockScalarKinds(tokens) - expectFlowAndBlockScalarRequiredKinds(tokens) - expectFlowAndBlockScalarForbiddenKinds(tokens) - } - - @Test("Plain scalars keep non-indicator hash and colon characters") - func test_plainScalarsKeepNonIndicatorHashAndColonCharacters() throws { - let tokens = try scanKinds( - """ - url: https://example.com/a:b - fragment: value#kept # removed - """, - ) - - expectKinds(tokens, [ - "streamStart", - "mappingKey", - "scalar value=\"url\" style=plain", - "mappingValue", - "scalar value=\"https://example.com/a:b\" style=plain", - "mappingKey", - "scalar value=\"fragment\" style=plain", - "mappingValue", - "scalar value=\"value#kept\" style=plain", - "comment value=\"removed\"", - "streamEnd", - ]) - expectContains(tokens, [ - "scalar value=\"https://example.com/a:b\" style=plain", - "scalar value=\"value#kept\" style=plain", - "comment value=\"removed\"", - ]) - expectDoesNotContain(tokens, [ - "scalar value=\"https\" style=plain", - "comment value=\"kept # removed\"", - ]) - } - - @Test("Scans directives and document markers without value tokens") - func test_directivesAndDocumentMarkers() throws { - let tokens = try scanKinds( - """ - %YAML 1.2 - %TAG !yaml! tag:yaml.org,2002: - --- - value: !yaml!str true - ... - """, - ) - - expectKinds(tokens, [ - "streamStart", - "documentStart", - "mappingKey", - "scalar value=\"value\" style=plain", - "mappingValue", - "tag value=tag:yaml.org,2002:str", - "scalar value=\"true\" style=plain", - "documentEnd", - "streamEnd", - ]) - expectDoesNotContain(tokens, [ - "scalar value=\"%YAML 1.2\" style=plain", - "scalar value=\"---\" style=plain", - "scalar value=\"...\" style=plain", - ]) - } - - @Test("Scans multiple document boundaries as tokens") - func test_multipleDocumentBoundaries() throws { - let tokens = try scanKinds( - """ - first: one - --- - - two - ... - # trailing - --- - """, - ) - - expectKinds(tokens, [ - "streamStart", - "mappingKey", - "scalar value=\"first\" style=plain", - "mappingValue", - "scalar value=\"one\" style=plain", - "documentStart", - "blockEntry", - "scalar value=\"two\" style=plain", - "documentEnd", - "comment value=\"trailing\"", - "documentStart", - "streamEnd", - ]) - expectContains(tokens, [ - "documentStart", - "documentEnd", - "comment value=\"trailing\"", - ]) - expectDoesNotContain(tokens, [ - "scalar value=\"---\" style=plain", - "scalar value=\"...\" style=plain", - ]) - } - - @Test("Tracks UTF-8 source marks") - func test_utf8SourceMarks() throws { - let tokens = try PureYAML.Parsing.Scanner().scan("caf\u{00E9}: yes") - guard let key = tokens.first(where: { - $0.kind == .scalar(value: "caf\u{00E9}", style: .plain) - }) else { - recordIssue("expected cafe scalar") - return - } - guard let value = tokens.first(where: { - $0.kind == .scalar(value: "yes", style: .plain) - }) else { - recordIssue("expected yes scalar") - return - } - - expectMarks(key, start: .init(line: 1, column: 1, index: 0), end: .init(line: 1, column: 5, index: 5)) - expectMarks(value, start: .init(line: 1, column: 7, index: 7), end: .init(line: 1, column: 10, index: 10)) - } - - @Test("Tracks ASCII and extended UTF-8 marks in one scan") - func test_asciiAndExtendedUTF8Marks() throws { - let tokens = try PureYAML.Parsing.Scanner().scan("ascii: abc\nemoji: 😀\nnext: ok") - guard let emoji = tokens.first(where: { - $0.kind == .scalar(value: "😀", style: .plain) - }) else { - recordIssue("expected emoji scalar") - return - } - guard let next = tokens.first(where: { - $0.kind == .scalar(value: "next", style: .plain) - }) else { - recordIssue("expected next scalar") - return - } - - expectMarks(emoji, start: .init(line: 2, column: 8, index: 18), end: .init(line: 2, column: 9, index: 22)) - expectMarks(next, start: .init(line: 3, column: 1, index: 23), end: .init(line: 3, column: 5, index: 27)) - } - - @Test("Reader advances UTF-8 marks across line breaks") - func test_readerAdvancesUTF8MarksAcrossLineBreaks() { - var reader = PureYAML.Parsing.Reader("a\u{00E9}\n\u{03B2}\r\nz") - - expectReaderMark(&reader, line: 1, column: 1, index: 0) - expectReaderMark(&reader, line: 1, column: 2, index: 1) - expectReaderMark(&reader, line: 1, column: 3, index: 3) - expectReaderMark(&reader, line: 2, column: 1, index: 4) - expectReaderMark(&reader, line: 2, column: 2, index: 6) - expectReaderMark(&reader, line: 3, column: 1, index: 8) - expectReaderMark(&reader, line: 3, column: 2, index: 9, advanceAfterCheck: false) - } - - @Test("Reports scanner errors") - func test_errorReporting() { - expectScannerError("root:\n child: yes\n wrong: no", .unexpectedIndentation(line: 3)) - expectScannerError("name: \"open", .unterminatedQuotedString(line: 1)) - expectScannerError("name: 'open", .unterminatedQuotedString(line: 1)) - expectScannerError("anchor: &", .expectedAnchorName(line: 1)) - expectScannerError("alias: *", .expectedAliasName(line: 1)) - expectScannerError("tag: ! [String] { - try PureYAML.Parsing.Scanner().scan(yaml).map(\.kind.description) -} - -private func expectKinds( - _ actual: [String], - _ expected: [String], -) { - #expect(actual == expected) -} - -private func expectContains( - _ actual: [String], - _ required: [String], -) { - for item in required { - #expect(actual.contains(item)) - } -} - -private func expectDoesNotContain( - _ actual: [String], - _ forbidden: [String], -) { - for item in forbidden { - #expect(!actual.contains(item)) - } -} - -private func expectMarks( - _ token: PureYAML.Parsing.Token, - start: PureYAML.Parsing.Mark, - end: PureYAML.Parsing.Mark, -) { - #expect(token.mark == start) - #expect(token.endMark == end) -} - -private func expectFlowAndBlockScalarKinds(_ tokens: [String]) { - expectKinds(tokens, [ - "streamStart", - "mappingKey", - "scalar value=\"flow\" style=plain", - "mappingValue", - "flowSequenceStart", - "tag value=!Thing", - "anchor name=item", - "scalar value=\"value\" style=doubleQuoted", - "flowEntry", - "alias name=item", - "flowEntry", - "flowMappingStart", - "mappingKey", - "scalar value=\"tagged\" style=plain", - "mappingValue", - "tag value=!", - "scalar value=\"it''s\" style=singleQuoted", - "flowMappingEnd", - "flowSequenceEnd", - "mappingKey", - "scalar value=\"text\" style=plain", - "mappingValue", - "blockScalarHeader style=literal chomping=keep", - "indent width=2", - "scalar value=\"line\" style=plain", - "dedent width=0", - "mappingKey", - "scalar value=\"folded\" style=plain", - "mappingValue", - "blockScalarHeader style=folded chomping=strip", - "indent width=2", - "scalar value=\"line\" style=plain", - "dedent width=0", - "streamEnd", - ]) -} - -private func expectFlowAndBlockScalarRequiredKinds(_ tokens: [String]) { - expectContains(tokens, [ - "flowSequenceStart", - "flowSequenceEnd", - "flowMappingStart", - "flowMappingEnd", - "tag value=!Thing", - "anchor name=item", - "alias name=item", - "blockScalarHeader style=literal chomping=keep", - "blockScalarHeader style=folded chomping=strip", - ]) -} - -private func expectFlowAndBlockScalarForbiddenKinds(_ tokens: [String]) { - expectDoesNotContain(tokens, [ - "comment value=\"removed\"", - "scalar value=\"tag:example.com,2026:thing\" style=plain", - ]) -} - -private func expectReaderMark( - _ reader: inout PureYAML.Parsing.Reader, - line: Int, - column: Int, - index: Int, - advanceAfterCheck: Bool = true, -) { - #expect(reader.mark == PureYAML.Parsing.Mark(line: line, column: column, index: index)) - if advanceAfterCheck { - reader.advance() - } -} - -private func expectScannerError( - _ yaml: String, - _ expected: PureYAML.Parsing.ParseError, -) { - expectError(expected) { - try PureYAML.Parsing.Scanner().scan(yaml) - } -} diff --git a/Tests/StreamParsingTests.swift b/Tests/StreamParsingTests.swift index 0b2c0d0..077e968 100644 --- a/Tests/StreamParsingTests.swift +++ b/Tests/StreamParsingTests.swift @@ -140,8 +140,11 @@ struct StreamParsingTests { ) } - @Test("Content after an explicit document end begins a new bare document") - func test_contentAfterExplicitDocumentEndBeginsBareDocument() throws { + @Test("Stream parser begins a new bare document after an explicit document end") + func test_streamParserBeginsNewBareDocumentAfterExplicitDocumentEnd() throws { + // A `...` end marker closes the current document; content that follows + // without a `---` starts a fresh bare document, matching YAML test-suite + // case 7Z25. let documents = try PureYAML.parseStream( """ name: First @@ -149,28 +152,34 @@ struct StreamParsingTests { name: Second """, ) - #expect(documents.count == 2) - #expect(documents[0].value == .mapping(.init([.init(key: "name", value: .string("First"))]))) - #expect(documents[1].value == .mapping(.init([.init(key: "name", value: .string("Second"))]))) + + #expect(documents == [ + .init(index: 0, value: .mapping(.init([ + .init(key: "name", value: .string("First")), + ]))), + .init(index: 1, value: .mapping(.init([ + .init(key: "name", value: .string("Second")), + ]))), + ]) } - @Test("Stream parser rejects extra root content without a document start") + @Test("Stream parser rejects extra root content after a completed node") func test_streamParserRejectsExtraRootContentWithoutDocumentStart() { - // A complete flow node followed by a bare scalar is extra content and needs an explicit - // `---` to start a new document. (Two bare plain lines such as `first` / `second` are not - // extra content; they correctly fold into a single multi-line plain scalar.) + // A flow node closes the document's single root node, so a bare scalar on + // the next line is extra content with no document boundary between it and + // the flow node. (Two bare plain lines instead fold into one scalar; see + // ParsingMultilineScalarTests.test_rootMultilinePlainScalarFolds.) expectStreamParseError( """ [1, 2] - extra + second """, - .unexpectedToken( - expected: "document boundary or stream end", - actual: "scalar value=\"extra\" style=plain", + .malformed( + reason: "did not find expected ", line: 2, column: 1, ), - description: "expected document boundary or stream end at line 2, column 1, found scalar value=\"extra\" style=plain", + description: "did not find expected at line 2, column 1", ) } diff --git a/Tests/TagHandleDiagnosticTests.swift b/Tests/TagHandleDiagnosticTests.swift index eb575d3..6fe236b 100644 --- a/Tests/TagHandleDiagnosticTests.swift +++ b/Tests/TagHandleDiagnosticTests.swift @@ -1,24 +1,23 @@ @testable import PureYAML import Testing -@Suite("Tag-handle diagnostics survive a scan abort") +@Suite("Undefined tag handles are parse errors") struct TagHandleDiagnosticTests { - @Test("An undeclared named tag handle is recorded as a diagnostic") - func test_undeclaredHandleRecorded() { - let issues = PureYAML.Parsing.Scanner().tagHandleIssues("key: !foo!bar\n") - #expect(issues.map(\.handle) == ["!foo!"]) + @Test("An undeclared named tag handle is rejected at parse time") + func test_undeclaredHandleRejected() { + // The ported engine is strict: a tag shorthand whose handle was never declared by a + // `%TAG` directive fails the parse, so the old permissive-parse scanner pre-pass + // (`Scanner.tagHandleIssues`) has no successor and no gap to fill. + #expect(throws: (any Error).self) { + _ = try PureYAML.parse("key: !foo!bar\n") + } } - @Test("Diagnostics collected before a scan-aborting error are still returned") - func test_diagnosticsSurviveScanAbort() throws { - // The undeclared `!foo!` handle records a diagnostic on the first line; the unterminated - // quote aborts the scan on the second. The accessor must still report the diagnostic gathered - // before the abort rather than dropping it, which a `try?` over the throwing scan once did. - let yaml = "key: !foo!bar\nnext: \"unterminated\n" - #expect(throws: PureYAML.Parsing.ParseError.self) { - _ = try PureYAML.Parsing.Scanner().scan(yaml) - } - let issues = PureYAML.Parsing.Scanner().tagHandleIssues(yaml) - #expect(issues.map(\.handle) == ["!foo!"]) + @Test("The validation report carries the undefined handle as a parse diagnostic") + func test_reportCarriesUndefinedHandle() { + let report = PureYAML.validationReport("key: !foo!bar\n") + let parseErrors = report.diagnostics.filter { $0.kind == .parse && $0.severity == .error } + #expect(parseErrors.count == 1) + #expect(parseErrors.first?.reason.contains("undefined tag handle") == true) } } diff --git a/Tests/UndefinedTagHandleTests.swift b/Tests/UndefinedTagHandleTests.swift index 2ba166a..f64ed60 100644 --- a/Tests/UndefinedTagHandleTests.swift +++ b/Tests/UndefinedTagHandleTests.swift @@ -2,10 +2,11 @@ import Testing /// A tag shorthand using a named handle (`!handle!suffix`) must be declared by a `%TAG` directive -/// in the document that uses it; the handle does not carry across documents. The parser stays -/// permissive (it still produces a value), so the violation surfaces as a diagnostic, not a parse -/// failure. These prove the diagnostic is exact: it fires for an undeclared handle and stays silent -/// for a declared one, a local tag, the secondary handle, and a `!x!` that is only scalar content. +/// in the document that uses it; the handle does not carry across documents. The ported engine is +/// strict (official suite case QLJ7): an undeclared handle fails the parse, and the validation +/// report carries it as a parse diagnostic. These prove the error is exact: it fires for an +/// undeclared handle and stays silent for a declared one, a local tag, the secondary handle, and a +/// `!x!` that is only scalar content. @Suite("Undefined tag handle") struct UndefinedTagHandleTests { private func codes(_ yaml: String) -> [String] { @@ -21,11 +22,14 @@ struct UndefinedTagHandleTests { --- !prefix!B c: d """ + // The ported engine is strict (official suite case QLJ7): the second document, which + // did not redeclare the handle, fails the parse, and the report carries that failure + // as a parse diagnostic instead of the old permissive-parse pre-pass diagnostic. let report = PureYAML.validationReport(yaml) - let undefined = report.diagnostics.filter { $0.code == "undefinedTagHandle" } - // The first document declared the handle; only the second, which did not, is flagged. - #expect(undefined.count == 1) - #expect(undefined.first?.line == 4) + let parseErrors = report.diagnostics.filter { $0.kind == .parse && $0.severity == .error } + #expect(parseErrors.count == 1) + #expect(parseErrors.first?.reason.contains("undefined tag handle") == true) + #expect(parseErrors.first?.line == 4) } @Test("A handle redeclared for each document is accepted with no diagnostic") diff --git a/Tests/UnsupportedYAMLGapsFixtures.swift b/Tests/UnsupportedYAMLGapsFixtures.swift index 85abf55..cd54f5e 100644 --- a/Tests/UnsupportedYAMLGapsFixtures.swift +++ b/Tests/UnsupportedYAMLGapsFixtures.swift @@ -58,23 +58,41 @@ enum UnsupportedYAMLGapsFixtures { expectedDescription: "multi-document streams are not supported at line 3", ), ParseErrorCase( - name: "tag directive after content", + // A directive must be followed by a `---` document start. A reserved + // or unknown directive is otherwise ignored, but here it is trailed + // by bare content rather than a document start, which is invalid. + name: "directive without a document start", + yaml: """ + %FOO bar + value: one + """, + expected: .malformed(reason: "did not find expected ", line: 2, column: 1), + expectedDescription: "did not find expected at line 2, column 1", + ), + ParseErrorCase( + // After document content has begun, a line starting with `%` is a + // misplaced directive (a plain scalar may not start with `%`). The + // first document ended implicitly, so the directive is rejected: a + // directive applies to the next document and requires a preceding `...`. + name: "percent after content is plain text not a directive", yaml: """ value: one %TAG !e! tag:example.com,2026: """, - expected: .unsupportedDirective(name: "%TAG", line: 2), - expectedDescription: "unsupported directive '%TAG' at line 2", + expected: .malformed(reason: "directives require a preceding document end marker", line: 2, column: 1), + expectedDescription: "directives require a preceding document end marker at line 2, column 1", ), ParseErrorCase( - name: "tag directive after document start", + // A directive after `---` ends that document implicitly, so it applies + // to the next document and requires a preceding `...` end marker. + name: "percent after document start is plain text not a directive", yaml: """ --- %TAG !e! tag:example.com,2026: value: !e!thing one """, - expected: .unsupportedDirective(name: "%TAG", line: 2), - expectedDescription: "unsupported directive '%TAG' at line 2", + expected: .malformed(reason: "directives require a preceding document end marker", line: 2, column: 1), + expectedDescription: "directives require a preceding document end marker at line 2, column 1", ), ] diff --git a/Tests/YAMLTestSuiteGapsTests.swift b/Tests/YAMLTestSuiteGapsTests.swift new file mode 100644 index 0000000..7ab9339 --- /dev/null +++ b/Tests/YAMLTestSuiteGapsTests.swift @@ -0,0 +1,397 @@ +import Foundation +@testable import PureYAML +import Testing + +/// Full conformance gate against the official YAML test suite +/// (github.com/yaml/yaml-test-suite, `data` branch, commit +/// 6ad3d2c62885d82fc349026c136ef560838fdf3d). Every official case (numbered +/// sub-cases counted) is vendored under `Fixtures/yaml-test-suite//` and +/// recorded in `Fixtures/yaml-test-suite-manifest.yaml` with a `status`: +/// +/// - `passing`: PureYAML already handles the case conformantly (it parses with a +/// value matching the JSON oracle when one is present, or it rejects an error +/// case). This is the regression guard: if a later change breaks the case, the +/// gated sweep fails. +/// - `gap`: PureYAML does not yet handle the case conformantly. The sweep asserts +/// the gap still reproduces, so a fix is forced to update the manifest rather +/// than silently drift. +/// +/// The behavioral sweep is gated behind `PUREYAML_RUN_YAML_TEST_SUITE=1`, mirroring +/// the full real-corpus sweep, so the default suite stays fast while the whole suite +/// is guarded on demand. The manifest-integrity test below is always on. +@Suite("YAML Test Suite Gaps") +struct YAMLTestSuiteGapsTests { + @Test("Manifest is consistent with its vendored fixture files") + func test_manifestMatchesVendoredFixtureFiles() throws { + let manifest = try YAMLTestSuiteManifest.load() + + #expect(manifest.version == 3) + #expect(manifest.cases.count == manifest.total) + #expect(manifest.total == 402) + #expect(Set(manifest.cases.map(\.id)).count == manifest.cases.count) + + let passing = manifest.cases.count(where: { $0.status == "passing" }) + let gaps = manifest.cases.count(where: { $0.status == "gap" }) + #expect(passing == manifest.passing) + #expect(gaps == manifest.gap) + #expect(passing + gaps == manifest.total) + + let rejects = manifest.cases.count(where: { $0.expected == "reject" }) + let parseOK = manifest.cases.count(where: { $0.expected == "parse-ok" }) + #expect(rejects + parseOK == manifest.total) + + for testCase in manifest.cases { + #expect(testCase.status == "passing" || testCase.status == "gap", "\(testCase.id): invalid status") + #expect(testCase.expected == "reject" || testCase.expected == "parse-ok", "\(testCase.id): invalid expected") + #expect(testCase.oracle == "json" || testCase.oracle == "none", "\(testCase.id): invalid oracle") + + let yaml = try testCase.loadInput() + #expect(yaml.utf8.count == testCase.byteCount, "\(testCase.id): byte count drift") + #expect(yaml.count(where: { $0 == "\n" }) == testCase.lineCount, "\(testCase.id): line count drift") + + if testCase.expected == "reject" { + #expect(testCase.loadErrorMarker() != nil, "\(testCase.id): reject case is missing its error marker") + } + if testCase.oracle == "json" { + #expect(testCase.loadExpectedJSON() != nil, "\(testCase.id): json oracle case is missing in.json") + } else { + #expect(testCase.loadExpectedJSON() == nil, "\(testCase.id): oracle is none but an in.json is present") + } + } + } + + @Test("Every case matches its recorded conformance status") + func test_everyCaseMatchesRecordedStatus() throws { + guard ProcessInfo.processInfo.environment["PUREYAML_RUN_YAML_TEST_SUITE"] == "1" else { + return + } + + let manifest = try YAMLTestSuiteManifest.load() + for testCase in manifest.cases { + let observed = try testCase.observedStatus() + #expect( + observed == testCase.status, + """ + \(testCase.id) "\(testCase.name)": manifest records status '\(testCase.status)' \ + but observed '\(observed)'. A 'passing' case that now fails is a regression; \ + a 'gap' case that now succeeds should be promoted to 'passing' in the manifest. + """, + ) + } + } +} + +// MARK: - Manifest + +struct YAMLTestSuiteManifest { + var version: Int + var total: Int + var passing: Int + var gap: Int + var cases: [YAMLTestSuiteCase] + + static func load() throws -> Self { + let url = try #require(Bundle.module.url( + forResource: "yaml-test-suite-manifest", + withExtension: "yaml", + subdirectory: "Fixtures", + )) + let value = try PureYAML.parse(String(contentsOf: url, encoding: .utf8)) + let root = try #require(value.mapping) + let version = try #require(root["version"]?.intValue) + let total = try #require(root["total"]?.intValue) + let passing = try #require(root["passing"]?.intValue) + let gap = try #require(root["gap"]?.intValue) + let caseValues = try #require(root.sequence("cases")) + return try YAMLTestSuiteManifest( + version: version, + total: total, + passing: passing, + gap: gap, + cases: caseValues.map(YAMLTestSuiteCase.init(value:)), + ) + } +} + +struct YAMLTestSuiteCase { + var id: String + var name: String + var localPath: String + var expected: String + var oracle: String + var status: String + var byteCount: Int + var lineCount: Int + + init(value: PureYAML.Model.Value) throws { + let mapping = try #require(value.mapping) + id = try mapping.requiredString("id") + name = try mapping.requiredString("name") + localPath = try mapping.requiredString("localPath") + expected = try mapping.requiredString("expected") + oracle = try mapping.requiredString("oracle") + status = try mapping.requiredString("status") + byteCount = try mapping.requiredInt("byteCount") + lineCount = try mapping.requiredInt("lineCount") + } + + private var caseSubdirectory: String { + let directory = localPath.split(separator: "/").dropLast().joined(separator: "/") + return "Fixtures/\(directory)" + } + + func loadInput() throws -> String { + let url = try #require(Bundle.module.url(forResource: "in", withExtension: "yaml", subdirectory: caseSubdirectory)) + return try String(contentsOf: url, encoding: .utf8) + } + + func loadErrorMarker() -> URL? { + Bundle.module.url(forResource: "error", withExtension: nil, subdirectory: caseSubdirectory) + } + + func loadExpectedJSON() -> String? { + guard let url = Bundle.module.url(forResource: "in", withExtension: "json", subdirectory: caseSubdirectory) else { + return nil + } + return try? String(contentsOf: url, encoding: .utf8) + } + + /// Recomputes PureYAML's present behavior for this case in the manifest's + /// `status` vocabulary, so any drift (a regression in a passing case, or a fix + /// that promotes a gap) is detectable. + /// + /// Conformance is decided by parsing alone: an error case is `passing` when the + /// parser rejects it; a value case is `passing` when the parser accepts it and, + /// when an in.json oracle is present, the parsed value matches it. Strict + /// validation (e.g. duplicate-key detection) is a separate, orthogonal concern + /// and is deliberately not part of the conformance decision. + func observedStatus() throws -> String { + let yaml = try loadInput() + var documents: [PureYAML.Stream.Document] = [] + var parseThrew = false + do { + documents = try PureYAML.parseStream(yaml) + } catch { + parseThrew = true + } + + if expected == "reject" { + return parseThrew ? "passing" : "gap" + } + if parseThrew { + return "gap" + } + guard oracle == "json", let jsonText = loadExpectedJSON() else { + return "passing" + } + // An empty in.json oracle means the conformant output is an empty stream + // (no JSON value), as for a comment-only or document-end-only input. A parser + // that yields any document then differs from the oracle, so it is a gap. + let trimmed = jsonText.trimmingCharacters(in: .whitespacesAndNewlines) + if trimmed.isEmpty { + return documents.isEmpty ? "passing" : "gap" + } + guard let expectedDocuments = decodeJSONStream(jsonText) else { + return "gap" + } + if expectedDocuments.count != documents.count { + return "gap" + } + let matches = zip(documents, expectedDocuments).allSatisfy { equalValue($0.value, $1) } + return matches ? "passing" : "gap" + } +} + +// MARK: - JSON oracle (type-preserving, avoids NSNumber bool ambiguity) + +indirect enum YAMLTestSuiteJSON: Decodable, Equatable { + case null + case bool(Bool) + case int(Int) + case double(Double) + case string(String) + case array([YAMLTestSuiteJSON]) + case object([String: YAMLTestSuiteJSON]) + + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if container.decodeNil() { + self = .null + } else if let value = try? container.decode(Bool.self) { + self = .bool(value) + } else if let value = try? container.decode(Int.self) { + self = .int(value) + } else if let value = try? container.decode(Double.self) { + self = .double(value) + } else if let value = try? container.decode(String.self) { + self = .string(value) + } else if let value = try? container.decode([YAMLTestSuiteJSON].self) { + self = .array(value) + } else if let value = try? container.decode([String: YAMLTestSuiteJSON].self) { + self = .object(value) + } else { + throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath, debugDescription: "unrecognized JSON")) + } + } +} + +func decodeJSONStream(_ text: String) -> [YAMLTestSuiteJSON]? { + let decoder = JSONDecoder() + if let whole = try? decoder.decode(YAMLTestSuiteJSON.self, from: Data(text.utf8)) { + return [whole] + } + let parts = splitJSONStream(text) + guard !parts.isEmpty else { + return nil + } + var values: [YAMLTestSuiteJSON] = [] + for part in parts { + guard let value = try? decoder.decode(YAMLTestSuiteJSON.self, from: Data(part.utf8)) else { + return nil + } + values.append(value) + } + return values +} + +/// Splits a concatenated JSON stream (one value per YAML document) into top-level values. +func splitJSONStream(_ text: String) -> [String] { + var scanner = JSONStreamScanner(text: text) + return scanner.scan() +} + +private struct JSONStreamScanner { + let text: String + var out: [String] = [] + var depth = 0 + var inString = false + var escaped = false + var start: String.Index? + + mutating func scan() -> [String] { + var index = text.startIndex + while index < text.endIndex { + if inString { + stepInString(text[index]) + } else { + stepStructural(text[index], at: index) + } + index = text.index(after: index) + } + if let begin = start { + out.append(String(text[begin...])) + } + return out.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }.filter { !$0.isEmpty } + } + + private mutating func stepInString(_ character: Character) { + if escaped { + escaped = false + } else if character == "\\" { + escaped = true + } else if character == "\"" { + inString = false + } + } + + private mutating func stepStructural(_ character: Character, at index: String.Index) { + switch character { + case "\"": + if start == nil { start = index } + inString = true + case "{", "[": + if start == nil { start = index } + depth += 1 + case "}", "]": + depth -= 1 + if depth == 0, let begin = start { + out.append(String(text[begin ... index])) + start = nil + } + case " ", "\n", "\r", "\t": + if depth == 0, let begin = start { + out.append(String(text[begin ..< index])) + start = nil + } + default: + if depth == 0, start == nil { start = index } + } + } +} + +func equalValue(_ value: PureYAML.Model.Value, _ json: YAMLTestSuiteJSON) -> Bool { + switch (value, json) { + case let (.sequence(lhs), .array(rhs)): + lhs.count == rhs.count && zip(lhs, rhs).allSatisfy { equalValue($0, $1) } + case let (.mapping(lhs), .object(rhs)): + equalMapping(lhs, rhs) + default: + equalScalar(value, json) + } +} + +private func equalScalar(_ value: PureYAML.Model.Value, _ json: YAMLTestSuiteJSON) -> Bool { + switch (value, json) { + case (.null, .null): + true + case let (.bool(lhs), .bool(rhs)): + lhs == rhs + case let (.int(lhs), .int(rhs)): + lhs == rhs + case let (.int(lhs), .double(rhs)): + Double(lhs) == rhs + case let (.double(lhs), .int(rhs)): + lhs == Double(rhs) + case let (.double(lhs), .double(rhs)): + lhs == rhs || (lhs.isNaN && rhs.isNaN) + case let (.string(lhs), .string(rhs)): + lhs == rhs + default: + false + } +} + +private func equalMapping(_ mapping: PureYAML.Model.Mapping, _ object: [String: YAMLTestSuiteJSON]) -> Bool { + guard mapping.pairs.count == object.count else { + return false + } + var dictionary: [String: PureYAML.Model.Value] = [:] + for pair in mapping.pairs { + dictionary[pair.key] = pair.value + } + guard dictionary.count == object.count else { + return false + } + for (key, expected) in object { + guard let actual = dictionary[key], equalValue(actual, expected) else { + return false + } + } + return true +} + +private extension PureYAML.Model.Mapping { + func requiredString(_ key: String) throws -> String { + try #require(self[key]?.stringValue) + } + + func requiredInt(_ key: String) throws -> Int { + try #require(self[key]?.intValue) + } +} + +private extension PureYAML.Model.Value { + var stringValue: String? { + guard case let .string(value) = self else { + return nil + } + return value + } + + var intValue: Int? { + guard case let .int(value) = self else { + return nil + } + return value + } +} diff --git a/docs/LIBYAML_PORT.md b/docs/LIBYAML_PORT.md new file mode 100644 index 0000000..92336fb --- /dev/null +++ b/docs/LIBYAML_PORT.md @@ -0,0 +1,71 @@ +# Faithful libyaml port + +## Status: complete and integrated + +The port is finished and is now PureYAML's **only** parsing engine. Every step +below has landed, the hand-rolled approximation has been deleted, and `parseEvents`, +`parseStreaming`, and `parseStreamStreaming` all run on the port. + +- **Faithfulness**: verified byte-for-byte against the libyaml reference event + dumper across all 308 vendored valid cases. The port matches libyaml on 307; the + single difference (`L24T/01`) is the port being more correct than libyaml. +- **Conformance** (canonical `test.event` gate, of 308): libyaml itself scores + 252, the old hand-rolled parser scored 267, and the port scores **275** after + closing real YAML 1.2 gaps libyaml lacks (reserved directives ignored with a + warning, newer `%YAML` minor versions, multi-line flow keys, bare documents + after `...`, tab-only blank lines, JSON UTF-16 surrogate-pair `\u` escapes, full + `ns-anchor-char` anchor/alias names). +- **Integration boundary** (`Sources/Parsing/Parser.Events.swift`): converts + libyaml's 0-based marks to PureYAML's 1-based, translates scanner/parser errors + to the diagnostic-aware `ParseError`, and enforces a 64-level nesting bound so + deep input throws `nestingTooDeep` rather than overflowing the recursive composer. + +Remaining open gaps and their clusters are tracked by `knownEventGaps` in +`Tests/CanonicalEventConformanceTests.swift`. + +## Why + +PureYAML's original scanner is a hand-rolled approximation of libyaml's +algorithm. Its bugs (block-mapping indentation, simple keys, empty values) are +the gap between that approximation and the proven reference. Rather than keep +patching the approximation, the scanner is being re-derived as a faithful, +function-by-function Swift port of libyaml's `scanner.c`, with the parser to +follow from `parser.c`. Correctness is then by construction: each Swift function +mirrors its C counterpart and is verified against libyaml directly. + +The constraint that PureYAML ships no C or generated runtime is preserved: this +is a translation of the algorithm into pure Swift, not a binding to libyaml. + +## Reference and verification + +- Source of truth: `PureYAMLResearch/Sources/CYaml/src/scanner.c` and `parser.c` + (libyaml 0.2.5). +- Oracle: the libyaml differential harness (`scratchpad/run_events.c` compiled + against the same `CYaml` source emits the canonical yeast event stream). Each + ported stage is checked token-for-token / event-for-event against it, in + addition to the vendored `test.event` suite ground truth. +- The port lands as a parallel implementation under `PureYAML.Parsing.LibYAML` + and is only swapped in for the current scanner once it matches the reference on + the full suite and the real-world corpus, so the working parser is never + regressed mid-port. + +## Order (each step verified before the next) + +1. **Indent engine** (DONE): `yaml_parser_roll_indent` / `yaml_parser_unroll_indent` + and the `indents` stack. A block collection opens only when content is strictly + more indented than the current level, which fixes the `- a:` / same-column `b:` + bug by construction. Implemented in `Sources/Parsing/LibYAML.IndentEngine.swift`, + unit-tested in `Tests/LibYAMLIndentEngineTests.swift`. +2. **Simple-key mechanism** (DONE): `save_simple_key`, `remove_simple_key`, + `stale_simple_keys`, the `simple_keys` stack and `simple_key_allowed` flag. +3. **Token-fetch core** (DONE): `fetch_more_tokens`, `fetch_next_token`, + `scan_to_next_token`, and the `fetch_*` dispatch (`fetch_key`, `fetch_value` + with its empty-scalar and roll-indent logic, `fetch_block_entry`, + `fetch_flow_*`, document indicators, stream start/end). +4. **Scalar scanners** (DONE): `scan_plain_scalar`, `scan_flow_scalar`, + `scan_block_scalar` (+ breaks), `scan_anchor`, `scan_tag`, `scan_directive`. +5. **Reader** (DONE): scalar-based `Reader` with `peek`/`skip`/`skipLine` and marks. +6. **Parser** (DONE): `parser.c` ported to compose events from the token stream. +7. **Integration** (DONE): `parseEvents` / `parseStream` run on the port and the + approximation has been deleted; the canonical event gate and libyaml + differential are green with zero regressions. diff --git a/docs/USAGE.md b/docs/USAGE.md index d8c3436..18eda3c 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -8,13 +8,13 @@ and typed-converting the YAML subset currently covered by the test corpus. Depend on the tagged package version: ```swift -.package(url: "https://github.com/mihaelamj/PureYAML.git", .upToNextMinor(from: "0.1.1")) +.package(url: "https://codeberg.org/Mihaela/PureYAML.git", .upToNextMinor(from: "0.1.1")) ``` For unreleased development snapshots, use the `main` branch: ```swift -.package(url: "https://github.com/mihaelamj/PureYAML.git", branch: "main") +.package(url: "https://codeberg.org/Mihaela/PureYAML.git", branch: "main") ``` Add the product to the target that reads or writes YAML: diff --git a/docs/YAML_TEST_SUITE_CONFORMANCE.md b/docs/YAML_TEST_SUITE_CONFORMANCE.md new file mode 100644 index 0000000..b56787f --- /dev/null +++ b/docs/YAML_TEST_SUITE_CONFORMANCE.md @@ -0,0 +1,431 @@ +# YAML Test Suite Conformance + +This document tracks PureYAML against the official +[YAML test suite](https://github.com/yaml/yaml-test-suite) and chronicles the +ordered plan that closed the gaps. The gap-closing work is complete: **all 402 +cases pass**, and the conformance gate guards the **entire** suite, not just the +formerly open gaps, so a fixed case can no longer silently regress. + +The machine-authoritative record is +`Tests/Fixtures/yaml-test-suite-manifest.yaml`. If this prose and the manifest +ever disagree, the manifest wins; update this document to match it, never the +other way around. + +## How conformance is measured + +The suite's `data` branch (commit `6ad3d2c62885d82fc349026c136ef560838fdf3d`) is +run against `PureYAML.parseStream`, with each case judged by its own oracle: + +- **error cases** (an `error` marker): a conformant parser must reject the input. +- **data cases** (an `in.json`): the parsed value must match the expected JSON + projection (core-schema resolved), compared structurally. An empty `in.json` + means the conformant output is an empty stream (no document). +- **plain valid cases** (neither): the input must parse without error. + +Conformance is decided by parsing alone. Strict validation (for example +duplicate-key detection in `PureYAML.validate`) is a separate, orthogonal concern +and is deliberately not part of the conformance decision, so a parseable document +that strict mode would reject is still counted as a passing parse. + +### The full-suite gate + +Earlier revisions tracked only the *failing* cases in a gap-only manifest and +deleted a case from it once fixed. That let later work silently regress an +already-fixed case, because nothing guarded it any longer. The gate is now +**comprehensive**: `Tests/Fixtures/yaml-test-suite-manifest.yaml` records *all* +402 cases (numbered sub-cases counted), each with its `id`, `name`, `localPath`, +the conformant `expected` behavior (`parse-ok` | `reject`), its `oracle` +(`json` | `none`), the input `byteCount` and `lineCount`, and a `status`: + +- `passing`: PureYAML handles the case conformantly today. +- `gap`: PureYAML does not yet handle it conformantly. + +Every case's files (`in.yaml`, plus `in.json` and/or `error`) are vendored under +`Tests/Fixtures/yaml-test-suite//`. The gated behavioral sweep asserts, for +**every** case, that a `passing` case still passes (the regression guard) and a +`gap` case still reproduces its non-conformant behavior (so a fix is forced to +update the manifest). A regression in any passing case now fails the sweep. + +### Result at the pinned commit + +402 cases (including numbered sub-cases): **402 passing, 0 gap**, per the +manifest header (`total: 402, passing: 402, gap: 0`). Run the opt-in sweep with: + +```sh +bash scripts/check-yaml-test-suite.sh +``` + +The default `swift test` only checks manifest/fixture/byte/line integrity and that +the recorded counts are consistent; the behavioral sweep is gated behind +`PUREYAML_RUN_YAML_TEST_SUITE=1`, the same way the full real-world corpus is gated. + +### Regressions repaired by the full-suite gate + +Making the gate comprehensive surfaced cases that had been fixed in an earlier +bucket and then silently regressed. All were repaired and set back to `passing`: + +- **Tab over-rejection.** A tab was being rejected wherever it appeared at a block + line start, over-rejecting valid forms. Per `scanner.c` (`scan_to_next_token`, + `scan_block_scalar_breaks`, `scan_plain_scalar`), a tab is illegal *only* as + block-structure indentation. Block indentation is now spaces-only; a tab is left + for the token scanner, which allows it (a) inside block-scalar content once the + content column is established by spaces (`96NN/00`, `96NN/01`, `R4YG`, + `Y79Y/001`), (b) as separation before a scalar value (`DK95/00`) or a flow node + (`6CA3`, `Q5MG`, `J3BT`), and (c) on a whitespace-only blank line (`DK95/03`, + `DK95/07`), while still rejecting genuine tab indentation (`4EJS`, `Y79Y/000`, + `Y79Y/004`-`/008`, `DK95/06`). The batch scanner and the incremental token cursor + were unified onto a single `scanStep`, since the divergence between them is what + let the streaming parser miss a tab error the batch scanner caught. +- **`26DV`** (anchors/aliases as mapping keys). An anchor on a `key:` value line + followed by an indented `*alias :` key was throwing, because the anchor was being + pushed onto the alias key (which cannot carry properties) instead of the nested + mapping. The alias-as-key path now attaches a property scanned on a prior line to + the enclosing mapping, and only rejects an alias that carries a property on its + own line (`&b *alias`, still correctly rejected by `SU74`). +- **`WZ62`** (flow rework). `{ foo : !!str, !!str : bar, }` mis-parsed the second + entry's bare-tag key into a mapping-as-key. A flow key introduced by a spliced + `mappingKey` now uses the same key parser as the implicit form, so a bare tag or + anchor before the `:` composes an empty tagged scalar key. + +## Failure categories (historical) + +While gaps were open they were tracked individually in the manifest and +clustered as: + +| Category | Meaning | +|---|---| +| false-reject | Well-formed YAML that PureYAML wrongly rejects at parse time. | +| json-mismatch | Parses, but produces a value that disagrees with the expected JSON. | +| accepted-invalid | Malformed YAML that PureYAML wrongly accepts (it should reject). | + +The last gaps to close included flow-context plain scalars that start with an +indicator (`[:x]` HM87/00, `[?x]` HM87/01, `{x: :x}` 58MP, `{?foo: bar}` 652Z), +non-ASCII and special-character anchor/alias names (`&😁` 8XYN, `&an:chor` Y2GN, +W5VH), multi-line flow keys (4MUZ/02, VJP3/01), and a few inputs that had to be +rejected but were accepted (DK4H, ZXT5, Y79Y/003, VJP3/00). All of these are +`status: passing` in the manifest today; the closing fix series is itemized in +`CHANGELOG.md`, and several of the final rejections (`QB6E`, `DK95/01`, +`Y79Y/003`, `S98Z`, `ZXT5`, `DK4H`) surpass libyaml, which mis-handles those +inputs. + +## Root-cause buckets and fix order + +Per `AGENTS.md`, every fix below must start from the matching behavior in the +private `PureYAMLResearch` repository (the libyaml-derived `Sources/CYaml/src/` +and the Yams Swift layer), not from re-derived intuition. The order is chosen so +that structural prerequisites land before the correctness work that depends on +them. + +### 1. Block scalar folding and chomping (DONE) + +Literal (`|`) and folded (`>`) scalar content now follows YAML 1.2 §8.1: interior +blank lines are preserved, §8.1.3 folding is applied (single break between equally +indented non-empty lines folds to a space; blank lines and more-indented lines keep +their breaks), tabs in content are preserved, and the `+` keep chomping indicator is +supported alongside clip and strip. The block scalar is scanned as a single unit +with indentation auto-detection, mirroring `scanner.c` +`yaml_parser_scan_block_scalar`. Implemented in `Sources/Parsing/Scanner.BlockScalar.swift`. + +Flipped 24 cases to passing: `4QFQ`, `5LLU`, `6VJK`, `7T8X`, `96NN/00`, `96NN/01`, +`DWX9`, `F6MC`, `F8F9`, `H2RW`, `JEF9/00`, `JEF9/01`, `K527`, `K858`, `L24T/00`, +`L24T/01`, `M29M`, `M9B4`, `MJS9`, `P2AD`, `R4YG`, `TS54`, `W9L4`, `Y79Y/001`. +(`T5N4` looks like a block-scalar case but is blocked by document-start handling, +bucket 5.) + +### 2. Quoted-scalar line breaks and empty-line folding (DONE) + +Single (`'`) and double (`"`) quoted multi-line scalars now apply YAML 1.2 flow +folding (§6.5, §7.3.1, §7.3.2): trailing whitespace before a break is stripped, +leading whitespace on a continuation line is stripped, a single break between +non-empty lines folds to one space, and N consecutive breaks yield N-1 literal +line feeds (the first and last lines keep their own leading and trailing spaces as +content). A double quoted backslash at end of line suppresses the break entirely. +The double quoted escape set is completed with `\xXX` and `\UXXXXXXXX`, plus the +previously missing `\0 \a \v \e`, literal `\`, and named breaks +`\N \_ \L \P` (the existing `\uXXXX` surrogate-pair handling is kept). The folding +state machine mirrors `scanner.c` `yaml_parser_scan_flow_scalar`; implemented in +`Sources/Parsing/Scalar.swift` (`foldFlowScalar` and the escape decoder). + +Flipped 30 cases to passing: `3RLN/00`, `3RLN/01`, `3RLN/02`, `3RLN/03`, +`3RLN/04`, `3RLN/05`, `4ZYM`, `565N`, `5GBF`, `6WPF`, `7A4E`, `8UDB`, `9SA2`, +`9TFX`, `DE56/00`, `DE56/01`, `DE56/02`, `DE56/03`, `DE56/04`, `DE56/05`, +`DK95/02`, `DK95/08`, `G4RS`, `NAT4`, `NP9H`, `PRH3`, `Q8AD`, `T4YY`, `TL85`, +`XV9V`. (`DK95/01` looks similar but is blocked by tab-as-indentation handling, +bucket 6.) + +### 3. Empty nodes and empty keys (DONE) + +Wherever a node is grammatically required but absent, the parser now composes an +empty (null) plain scalar instead of raising "expected a YAML node", mirroring +`parser.c`'s `yaml_parser_process_empty_scalar` fallback. The single production +covers every missing-node position: after a tag or anchor property with no +following node, an absent mapping value, an absent mapping key (both the plain +`: value` form and the explicit `?` form), and the empty key and value forms +inside flow collections (`{ : }`, `{ , : v }`, `{ k : !!str , }`). An empty node +that carries an anchor or tag is explicit; a bare absent node with no property in +a grammatically-required position is still a parse error, matching the reference +parser's "did not find expected node content". The empty scalar resolves through +the normal scalar resolver against an empty value, so `!!str` yields `""`, +`!!null` and a bare empty yield null, and an empty key resolves like any other +empty scalar. Implemented in `Sources/Parsing/TokenEventParser.EmptyNode.swift` +with call sites in `TokenEventParser.swift`, `TokenEventParser.Block.swift`, +`TokenEventParser.Flow.swift`, and `TokenEventParser.Helpers.swift`. + +Flipped 20 cases to passing: `2JQS`, `2XXW`, `5WE3`, `6M2F`, `7W2P`, `BU8L`, +`CFD4`, `JTV5`, `KK5P`, `LE5A`, `M2N8/00`, `NHX8`, `NKF9`, `PW8X`, `RZP5`, `S3PD`, +`SM9W/01`, `UKK6/02`, `WZ62`, `XW4D`. (`CT4Q` no longer false-rejects but its +flow multi-line plain-scalar key still folds incorrectly, so it moves from +`false-reject` to `json-mismatch` rather than passing; that fold is a separate +flow-scanning gap.) + +### 4. Anchors, tags, and aliases as mapping keys (DONE) + +A mapping key is a full node: it may carry `&anchor` and/or `!tag` properties and +may itself be an `*alias`. These were rejected with "expected document boundary" +/ "expected mapping key" / "undefined alias". Four root causes were fixed: + +1. **Anchor/alias name termination.** The scanner consumed the name up to a + whitespace or flow indicator but not `:`, so `*alias:` read the alias name as + `alias:`. It now terminates the name at the first character outside libyaml's + `IS_ALPHA` set (ASCII letters, digits, `-`, `_`), mirroring + `yaml_parser_scan_anchor`, so the trailing `:` is a mapping indicator. +2. **Properties/alias in key position.** The block-mapping parser only began a + pair at the key indicator, but the scanner emits a key's anchor/tag *before* + that indicator (and an alias key has no indicator at all). The parser now + begins a pair at leading properties or an alias, and properties on the same + line as the first key attach to that key node, not to the mapping (`&a a: b` + anchors the key `a`; `&a` alone on its own line anchors the map). +3. **Anchor on an empty value.** An anchor or tag at value position with no node + following on the same line now composes an empty (null) value that carries the + property, so `a: &anchor` registers `anchor` as null and a later `*anchor` + resolves to null instead of raising "undefined alias". +4. **Resolved-value registration.** An anchored scalar registers its resolved + value (an empty anchored scalar registers null, not `""`). The implicit-key + scanner also now recognizes a key with trailing spaces before its `:`. + +- **Reference:** the block + flow mapping productions in `parser.c`, + `yaml_parser_scan_anchor` for name termination, and Yams' `Constructor` anchor + table for resolution semantics. + +Flipped 10 cases to passing: `26DV`, `6KGN`, `74H7`, `87E4`, `9KAX`, `E76Z`, +`G9HC`, `HMQ5`, `LQZ7`, `ZWK4`. (`G9HC` is an invalid-anchor-in-zero-indented- +sequence case that is now correctly *rejected*.) `2SXE` no longer false-rejects +but its compact block-mapping structure still disagrees with the expected JSON, +so it moved from `false-reject` to `json-mismatch` rather than passing; that +structure is a separate compact-mapping gap. + +### 5. Directives and document boundaries (DONE) + +Directives are now handled and the `...` document-end marker may be followed by a +new document. Three root causes were fixed: + +1. **`%` position detection.** A `%` begins a directive only in directive + position: before any document content and before the `---` that starts a + document (which includes the position immediately after a `...` end marker). + After content, after `---`, or in any flow context, `%` is ordinary plain + text. The scanner previously treated `%` at column 1 as a directive + unconditionally and rejected it once content had begun, mis-firing on + `XLQ9`, `UT92`, `W4TN`, `6ZKB`, `9DXL`. This mirrors `scanner.c`, which only + enters `yaml_parser_scan_directive` from the start-of-line directive context. +2. **Lenient directive parsing.** `%YAML` accepts a `1.x` version (a higher minor + is treated as 1.2 with a warning, not an error, so `%YAML 1.3` parses) while + rejecting an unsupported major version, a duplicate `%YAML` in one document, + or extra non-comment fields. Reserved and unknown directives, and `%TAG` + handle definitions, are accepted and ignored. A directive must be followed by + a `---` document start. This follows `parser.c` `process_directives` (duplicate + and version checks) but relaxes the unknown-directive and minor-version errors + to the spec's reserved-directive warning behavior. +3. **Document end then new document.** A `...` end marker closes the current + document; content that follows (with or without an explicit `---`) starts a + fresh document in the multi-document stream parser. The scanner no longer + rejects this as an unsupported multi-document stream; the single-document + `parse` still rejects multi-document input at compose time. + +Implemented in `Sources/Parsing/Scanner.Directives.swift` (directive scanning, +`%` position gate, `...` boundary), `Sources/Parsing/TokenEventParser.swift` +(a `...` end marker returns to start a new document), and +`Sources/Parsing/TokenCursor.swift` (the streaming scanner rejects a pending +directive at end of stream). The new `directiveWithoutDocument` `ParseError` +covers a directive with no following `---`. + +- **Reference:** `scanner.c` `yaml_parser_scan_directive` / + `yaml_parser_scan_version_directive_value` + `parser.c` + `yaml_parser_process_directives` and the document-start state machine. + +Flipped 11 cases to passing with matching values: `2LFX`, `5TYM`, `6WLZ`, +`6ZKB`, `7Z25`, `9DXL`, `9WXW`, `BEC7`, `MUS6/03`, `MUS6/05`, `MUS6/06`. +Correctly *rejected* four cases that were previously accepted-invalid: `9MMA` +and `B63P` (directive without a document), `H7TQ` (extra words on `%YAML`), and +`SF5V` (duplicate `%YAML`). `6LVF` and `W4TN` no longer parse-error but their +values still disagree with the expected JSON, so they moved from `false-reject` +to `json-mismatch`: `6LVF` needs same-line content after `---` (the `KSS4` +"scalars on `---` line" gap) and `W4TN` needs literal block-scalar clip chomping +to keep the trailing newline (the `T5N4`/`4WA9` literal-scalar gap). `XLQ9` and +`UT92` no longer mis-fire on `%` but still parse-error on top-level and flow +multi-line plain-scalar folding respectively (the `9YRD`/`EX5H` and `NJ66` +gaps), so they remain recorded. `%TAG` shorthand *resolution* (rejecting a +handle used in a later document where it is undefined, e.g. `QLJ7`) is left to +the tag-resolution work and those cases stay recorded as accepted-invalid. + +### 6. Stricter rejection of invalid input (DONE) + +Inputs that must be rejected were silently accepted: tabs used as indentation, +document markers inside quoted scalars or flow collections, an anchor on an +alias, and overlapping directive sections. Grounded in the error productions in +`scanner.c`/`parser.c`, this bucket tightened the scanner and event parser: + +- **Tabs as indentation.** A tab may never supply block-structure indentation + (YAML 1.2 `s-indent` is spaces only). `Sources/Parsing/Scanner.Indentation.swift` + rejects a tab at the start of a block line; `Scanner.BlockScalar.swift` rejects + a tab where a block-scalar indentation space is expected + (`scanner.c:2993`); and `Scanner.Tabs.swift` rejects a tab in separation + position only when a nested block node follows (a `-` entry, a `?` key, or a + compact mapping key), while leaving a tab that merely separates an indicator + from a scalar *value* valid. The `IS_BLANKZ` boundary fix (`scanner.c:1948`) + also lets `:`/`-`/`?` be recognized when followed by a tab. +- **Document markers in scalars/flow.** A `---`/`...` marker at column 0 inside an + open quoted scalar (`scanner.c:3058`) or an open flow collection is rejected in + `Scanner.swift`/`Scanner.Directives.swift` rather than silently ending the + document. +- **Overlapping directive sections.** A `%YAML`/`%TAG` line that opens a second + explicit document with no intervening `...` suffix is rejected + (`Scanner.Directives.swift`), matching the grammar's `l-document-suffix` rule. +- **Anchor on an alias.** An alias cannot carry an anchor or tag, and an + anchor-plus-alias on one node is rejected (`TokenEventParser.swift`), mirroring + the alias-first branch of `yaml_parser_parse_node` (`parser.c:563`). + +Rejected (removed from the gap manifest): `4EJS`, `5TRB`, `MUS6/01`, `N782`, +`RXY3`, `SR86`, `SU74`, `Y79Y/000`, `Y79Y/004`, `Y79Y/005`, `Y79Y/006`, +`Y79Y/008`, `Y79Y/009`. Four of these (`9MQT/01` aside) were the bucket-3..5 +regressions; `MUS6/01`, `N782`, `SU74`, and `Y79Y/009` are repaired here. The tab +boundary fix also flipped `6BCT` and `Y79Y/010` to passing and moved `DC7X` and +`J3BT` from `false-reject` to `json-mismatch` (they now parse but still need +trailing-tab scalar trimming and tab-in-quoted-scalar handling to match exactly). + +Deferred at this stage (to avoid regressing valid input or the default suite), +and closed later by the final series (section 9): + +- **`---`-line content** is dropped by the scanner (`skipLine`), so cases whose + invalidity lives in content after a `---`/`...` on the same line are not yet + reachable: `9MQT/01`, `2G84/00`, `2G84/01`, `CXX2`, and `QLJ7` (per-document + `%TAG` handle scoping). Fixing these means scanning `---`-line content, which + touches the document-content path used by many valid cases. +- **Full simple-key / multi-colon tracking** is needed for `ZCZ6`, `ZL4Z`, + `9KBC`, and the other "two colons on one line" / wrong-indent mapping cases. +- **Flow trailing-junk** (`9JBA`, `CVW2`, `62EZ`, `P2EQ`) and assorted scalar + edge cases (`SU5Z`, `X4QW`, `JY7Z`, `HU3P`, `DK95/01`, `Y79Y/003`, ...) remain. + +- **Reference:** the corresponding error productions in `scanner.c`/`parser.c`. +- **Why last among the parse work:** several of these only become reachable once + buckets 1-5 stop short-circuiting; tightening errors earlier would mask the + positive-case work. + +### 7. Document-root multi-line plain and block scalars (DONE) + +A multi-line plain scalar folded correctly as a mapping value or sequence item but +not as the document's own root node, and a block scalar header on the `---` line +(`--- |`, `--- >`) was discarded. Both stemmed from the scanner not modelling +libyaml's `parser->indent` (the enclosing block-collection column, -1 at the bare +root). The scanner now tracks that block indent separately from per-line +indentation: it rolls on a block sequence entry, an implicit/explicit mapping key, +and unrolls at each block-line start and at every document boundary. Plain-scalar +continuation folding compares against this block indent, so a root scalar folds its +column-0 continuations while a collection member still ends at a sibling line, and a +mapping value whose continuation sits at its own column (`4CQQ`) folds. A `---` +start marker no longer skips the rest of its line; its trailing content is scanned +as the document's root node (`--- foo`, `--- [1, 2]`, `--- |`, `--- >`), and a block +scalar whose body sits at the root's column 0 captures that body and ends at the +next `---`/`...` marker. + +Fixed false-rejects (now parse with matching values): `35KP`, `4CQQ`, `4Q9F`, +`6JQW`, `82AN`, `93WF`, `96L6`, `9MQT/00`, `9YRD`, `B3HG`, `DK3J`, `EX5H`, `EXG3`, +`FP8R`, `RZT7`, `T26H`, `UGM3`, `XLQ9`. Corrected previously mismatched values: +`27NA`, `2G84/02`, `2G84/03`, `4WA9`, `6FWR`, `6LVF`, `A2M4`, `K54U`, `KSS4`, +`L383`, `T5N4`, `W4TN`. Now correctly *rejected* (were accepted-invalid): `9KBC`, +`ZVH3`, `9MQT/01`. Headline 305 -> 338 pass; categories drop to false-reject 18, +json-mismatch 10, accepted-invalid 36. + +Two cases parsed but still mismatched at this stage and stayed `json-mismatch` +until the final series (section 9): `M7A3` (a bare document followed by +`...`-delimited empty documents splits into one extra document) and `NB6Z` (tabs +on the empty lines of a multi-line plain scalar must fold to newlines rather +than survive as literal tabs). + +- **Reference:** `yaml_parser_scan_plain_scalar` and the `parser->indent` + roll/unroll logic (`yaml_parser_roll_indent`/`yaml_parser_unroll_indent`), plus + block-scalar indent detection in `scanner.c`. + +### 8. Flow-collection completeness (DONE) + +Flow mappings and sequences now accept keys of any node kind, empty keys and +values, and multi-line scalar keys, matching libyaml's flow productions. The +scanner implements libyaml's simple-key mechanism for flow context: it records a +potential key position before scanning a plain/quoted scalar, an anchor/tag, or a +`[`/`{` opener (when a simple key is allowed there), and a later `:` value +indicator splices a `mappingKey` token in front of that node. In flow context a +`:` is always a value indicator and a `?` always an explicit key indicator +regardless of the following character (libyaml's `flow_level || IS_BLANKZ_AT`), +so adjacent forms (`"k":v`, `{k}:v`) and a trailing `?` parse; the block-only +implicit-key forward lookahead no longer fires in flow. A multi-line plain key +folds in full before its `:` is read. The flow parser was rebuilt around +`flow_sequence_entry`/`flow_mapping_key`/`flow_mapping_value`, composing empty +scalars where a key or value is absent. The streaming token cursor keeps an open +flow collection's tokens buffered until it closes so the retroactive key splice +stays valid. + +Fixed false-rejects (now parse, values match where an oracle exists): `4FJ6`, +`8KB6`, `9BXH`, `9MMW`, `CN3R`, `DFF7`, `FRK4`, `NJ66`, `UT92`. Corrected the +`json-mismatch` `CT4Q` (spec example 7.20, single-pair explicit entry) to a +matching value. Headline 338 -> 348 pass; categories drop to false-reject 9, +json-mismatch 9, accepted-invalid 36. + +Deferred at this stage and closed later by the final series (section 9): +`LX3P` (`[flow]: block`) and `6BFJ` (`&key [ ... ]: value`) use a flow +collection as a *block* mapping key, which needed the simple-key splice in +block context, a separate change with its own regression surface. The +flow-internal `7ZZ5` mismatch was a block-sequence nesting issue (`- - - []`), +not flow, and stayed `json-mismatch` until then. + +- **Reference:** `yaml_parser_save_simple_key`, `yaml_parser_fetch_value` + (KEY-token splice), `yaml_parser_fetch_key`, the flow-collection + start/end and flow-entry fetches in `scanner.c`, and the + `yaml_parser_parse_flow_*` productions in `parser.c`. + +### 9. The libyaml port and the closing series: 348 -> 402 (DONE) + +The buckets above were fixed on the original hand-rolled scanner and token +parser. That engine was then replaced wholesale: a faithful Swift port of +libyaml's scanner and parser landed under `PureYAML.Parsing.LibYAML` +(`docs/LIBYAML_PORT.md`), was verified against libyaml built from source, and +became the sole parsing engine; the hand-rolled `Scanner.*` and +`TokenEventParser.*` files named in buckets 1-8 no longer exist, so those +references are historical. + +On the ported engine, a final fix series closed the remaining 54 cases, +itemized in `CHANGELOG.md`: stricter rejection of under-indented or +tab-indented continuations in quoted scalars, tab-indented flow content, +mis-indented leading empty lines in block scalars, multi-line implicit keys in +flow sequences, block sequences opening mid-line after another node, full +YAML 1.2 anchor and alias names, and the remaining flow-key and `---`-line +content gaps. Several of these rejections +(`QB6E`, `DK95/01`, `Y79Y/003`, `S98Z`, `ZXT5`, `DK4H`) surpass libyaml itself, +which accepts the malformed input. The result is the manifest's current state: +**402 passing, 0 gap**. + +## Updating this document + +When a fix lands: + +1. Re-run `bash scripts/check-yaml-test-suite.sh`; it will fail on the now-fixed + cases (a `gap` whose behavior changed) and on any case the change regressed (a + `passing` case that now fails). +2. For each newly-passing case, assert the round-trip law (parse → dump → parse is + stable) in addition to the value/JSON match, per + `core/round-trip-transformation.md`; the parser fix is only proven once the + emitter agrees on the same input. +3. Flip those cases' `status` to `passing` in + `Tests/Fixtures/yaml-test-suite-manifest.yaml`. Do **not** delete a case or its + vendored fixtures: the whole suite stays vendored and guarded so a future change + cannot silently regress a fixed case. +4. Update the `passing` / `gap` counts in the manifest header and in this document + and `CHANGELOG.md`. diff --git a/docs/releases/pureyaml-0-1-0.md b/docs/releases/pureyaml-0-1-0.md index de0ef5b..19083ca 100644 --- a/docs/releases/pureyaml-0-1-0.md +++ b/docs/releases/pureyaml-0-1-0.md @@ -64,5 +64,5 @@ Windows build and test, and WASM build checks. ## Installation ```swift -.package(url: "https://github.com/mihaelamj/PureYAML.git", .upToNextMinor(from: "0.1.0")) +.package(url: "https://codeberg.org/Mihaela/PureYAML.git", .upToNextMinor(from: "0.1.0")) ``` diff --git a/docs/releases/pureyaml-0-1-1.md b/docs/releases/pureyaml-0-1-1.md index 5cd19df..e5d46d9 100644 --- a/docs/releases/pureyaml-0-1-1.md +++ b/docs/releases/pureyaml-0-1-1.md @@ -38,5 +38,5 @@ The release process requires: ## Installation ```swift -.package(url: "https://github.com/mihaelamj/PureYAML.git", .upToNextMinor(from: "0.1.1")) +.package(url: "https://codeberg.org/Mihaela/PureYAML.git", .upToNextMinor(from: "0.1.1")) ``` diff --git a/docs/releases/pureyaml-0-1-2.md b/docs/releases/pureyaml-0-1-2.md index 80569f4..8ce2da0 100644 --- a/docs/releases/pureyaml-0-1-2.md +++ b/docs/releases/pureyaml-0-1-2.md @@ -45,5 +45,5 @@ The release candidate was locally verified with: ## Installation ```swift -.package(url: "https://github.com/mihaelamj/PureYAML.git", .upToNextMinor(from: "0.1.2")) +.package(url: "https://codeberg.org/Mihaela/PureYAML.git", .upToNextMinor(from: "0.1.2")) ``` diff --git a/scripts/check-forbidden-patterns.sh b/scripts/check-forbidden-patterns.sh index 51af3e2..4f3a136 100644 --- a/scripts/check-forbidden-patterns.sh +++ b/scripts/check-forbidden-patterns.sh @@ -32,10 +32,14 @@ package_forbidden=$( ) report_matches "Package.swift must not declare external, binary, or system-library targets" "$package_forbidden" +# The core PureYAML target stays standard-library-only and imports nothing. The +# layered PureYAMLJSON target builds on the core, so it may import the first-party +# PureYAML module (and only that); no Foundation, no external, no system modules. source_imports=$( - grep -RInE '^[[:space:]]*import[[:space:]]+[A-Za-z_][A-Za-z0-9_]*' Sources --include '*.swift' 2>/dev/null || true + grep -RInE '^[[:space:]]*import[[:space:]]+[A-Za-z_][A-Za-z0-9_]*' Sources --include '*.swift' 2>/dev/null \ + | grep -vE '^Sources/PureYAMLJSON/[^:]+:[0-9]+:[[:space:]]*import[[:space:]]+PureYAML[[:space:]]*$' || true ) -report_matches "Sources must stay standard-library-only and import no modules" "$source_imports" +report_matches "Sources must stay standard-library-only (only PureYAMLJSON may import the core PureYAML module)" "$source_imports" source_platform_branches=$( grep -RInE '^[[:space:]]*#if[[:space:]]+(os|canImport)[[:space:]]*\(' Sources --include '*.swift' 2>/dev/null || true @@ -73,11 +77,12 @@ report_matches "Sources must not use traps, forced casts, try!, or force unwraps test_imports=$( grep -RInE '^[[:space:]]*(@testable[[:space:]]+)?import[[:space:]]+[A-Za-z_][A-Za-z0-9_]*' Tests --include '*.swift' 2>/dev/null \ - | grep -vE '^[^:]+:[0-9]+:[[:space:]]*@testable[[:space:]]+import[[:space:]]+PureYAML[[:space:]]*$' \ + | grep -vE '^[^:]+:[0-9]+:[[:space:]]*@testable[[:space:]]+import[[:space:]]+PureYAML(JSON)?[[:space:]]*$' \ + | grep -vE '^[^:]+:[0-9]+:[[:space:]]*import[[:space:]]+PureYAML[[:space:]]*$' \ | grep -vE '^[^:]+:[0-9]+:[[:space:]]*import[[:space:]]+Foundation[[:space:]]*$' \ | grep -vE '^[^:]+:[0-9]+:[[:space:]]*import[[:space:]]+Testing[[:space:]]*$' || true ) -report_matches "Tests may import only Foundation, Testing, and @testable PureYAML" "$test_imports" +report_matches "Tests may import only Foundation, Testing, PureYAML, and @testable PureYAML/PureYAMLJSON" "$test_imports" test_xctest=$( grep -RInE '\bXCTest(Case|Expectation)?\b|\bXCTAssert[A-Za-z]*\b|^[[:space:]]*import[[:space:]]+XCTest[[:space:]]*$' Tests --include '*.swift' 2>/dev/null || true diff --git a/scripts/check-yaml-test-suite.sh b/scripts/check-yaml-test-suite.sh new file mode 100755 index 0000000..7737608 --- /dev/null +++ b/scripts/check-yaml-test-suite.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Runs the opt-in conformance sweep over the full vendored YAML test suite. +# Tests/Fixtures/yaml-test-suite-manifest.yaml records all 402 cases with a +# `status` (passing | gap); the sweep verifies every passing case still passes +# (the regression guard) and every gap still reproduces, so any fix or regression +# is forced to update the manifest. + +PUREYAML_RUN_YAML_TEST_SUITE=1 swift test --filter YAMLTestSuiteGapsTests