rlsp_yaml_parser/event.rs
1// SPDX-License-Identifier: MIT
2
3//! High-level parse events produced by the streaming parser.
4//!
5//! The public entry point is [`crate::parse_events`], which returns an
6//! iterator of <code>Result<([Event], [crate::pos::Span]), [crate::error::Error]></code>.
7//!
8//! Each event carries a [`crate::pos::Span`] covering the input bytes that
9//! contributed to it. For zero-width synthetic events (e.g. `StreamStart`
10//! at the very beginning of input), the span has equal `start` and `end`.
11//!
12
13use std::borrow::Cow;
14
15use crate::pos::Span;
16
17/// Block scalar chomping mode per YAML 1.2 §8.1.1.2.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum Chomp {
20 /// `-` — trailing newlines stripped.
21 Strip,
22 /// (default, no indicator) — single trailing newline kept.
23 Clip,
24 /// `+` — all trailing newlines kept.
25 Keep,
26}
27
28/// The style (block or flow) of a collection (sequence or mapping).
29///
30/// Currently only `Block` is produced; `Flow` will be used when flow sequences
31/// (`[a, b]`) and flow mappings (`{a: b}`) are implemented in Task 14.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum CollectionStyle {
34 /// A block-style collection using indentation and `-`/`:` indicators.
35 Block,
36 /// A flow-style collection using `[]` or `{}` delimiters (Task 14).
37 Flow,
38}
39
40/// The style in which a scalar value was written in the source.
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum ScalarStyle {
43 /// An unquoted plain scalar (YAML 1.2 §7.3.3).
44 Plain,
45 /// A `'single-quoted'` scalar (YAML 1.2 §7.3.2).
46 SingleQuoted,
47 /// A `"double-quoted"` scalar (YAML 1.2 §7.3.1).
48 DoubleQuoted,
49 /// A `|` literal block scalar (YAML 1.2 §8.1.2).
50 Literal(Chomp),
51 /// A `>` folded block scalar (YAML 1.2 §8.1.3).
52 ///
53 /// Line folding is applied to the collected content: a single line break
54 /// between two equally-indented non-blank lines becomes a space; N blank
55 /// lines between non-blank lines produce N newlines; more-indented lines
56 /// preserve their relative leading whitespace and the line break before
57 /// them is kept as `\n` rather than folded to a space. Callers must not
58 /// treat the value as whitespace-safe — more-indented lines can inject
59 /// arbitrary leading spaces into the parsed value.
60 Folded(Chomp),
61}
62
63/// A high-level YAML parse event.
64#[derive(Debug, Clone, PartialEq, Eq)]
65pub enum Event<'input> {
66 /// The YAML stream has started.
67 ///
68 /// Always the first event in any parse. The associated span is a
69 /// zero-width span at [`crate::pos::Pos::ORIGIN`].
70 StreamStart,
71 /// The YAML stream has ended.
72 ///
73 /// Always the last event in any parse. The associated span is a
74 /// zero-width span at the position immediately after the last byte of
75 /// input.
76 StreamEnd,
77 /// A YAML comment (YAML 1.2 §6.6).
78 ///
79 /// `text` is the comment body — the content of the line after the `#`
80 /// character, with the `#` itself excluded. Leading whitespace after `#`
81 /// is preserved (e.g. `# hello` → text `" hello"`; `#nospace` → text
82 /// `"nospace"`). The associated span covers from the `#` character
83 /// through the last byte of comment text (the newline is not included).
84 ///
85 /// One `Comment` event is emitted per physical line.
86 Comment {
87 /// Comment body (everything after the `#`, excluding the newline).
88 text: &'input str,
89 },
90 /// An alias node (`*name`) that references a previously anchored node.
91 ///
92 /// The associated span covers the entire `*name` token (from `*` through
93 /// the last character of the name). Resolution of the alias to its
94 /// anchored node is the loader's responsibility (Task 20) — the parser
95 /// emits this event without expansion.
96 Alias {
97 /// The anchor name being referenced (e.g. `"foo"` for `*foo`).
98 /// Borrowed directly from input — no allocation.
99 name: &'input str,
100 },
101 /// A document has started.
102 ///
103 /// `explicit` is `true` when the document was introduced with `---`.
104 /// `false` for bare documents (no marker).
105 DocumentStart {
106 /// Whether the document was introduced with `---`.
107 explicit: bool,
108 /// Version from the `%YAML` directive preceding this document, if any.
109 ///
110 /// `Some((1, 2))` for `%YAML 1.2`, `None` when no `%YAML` directive was present.
111 version: Option<(u8, u8)>,
112 /// Tag handle/prefix pairs from `%TAG` directives preceding this document.
113 ///
114 /// Each entry is `(handle, prefix)` — e.g. `("!foo!", "tag:example.com,2026:")`.
115 /// Empty when no `%TAG` directives were present.
116 tag_directives: Vec<(String, String)>,
117 },
118 /// A document has ended.
119 ///
120 /// `explicit` is `true` when the document was closed with `...`.
121 /// `false` for implicitly-ended documents.
122 DocumentEnd {
123 /// Whether the document was closed with `...`.
124 explicit: bool,
125 },
126 /// A block or flow sequence has started.
127 ///
128 /// Followed by zero or more node events (scalars or nested collections),
129 /// then a matching [`Event::SequenceEnd`].
130 SequenceStart {
131 /// The anchor name, if any (e.g. `&foo`).
132 anchor: Option<&'input str>,
133 /// Source span of the `&name` anchor token — from `&` through the last
134 /// byte of the name. `Some` when `anchor` is `Some`, `None` otherwise.
135 anchor_loc: Option<Span>,
136 /// The resolved tag, if any (e.g. `"tag:yaml.org,2002:seq"` for `!!seq`).
137 ///
138 /// Verbatim tags (`!<URI>`) borrow from input. Shorthand tags resolved
139 /// via `%TAG` directives or the built-in `!!` default produce owned strings.
140 tag: Option<Cow<'input, str>>,
141 /// Source span of the tag token — from `!` through the last byte of the
142 /// tag token. `Some` when `tag` is `Some`, `None` otherwise.
143 tag_loc: Option<Span>,
144 /// Whether this is a block (`-` indicator) or flow (`[...]`) sequence.
145 style: CollectionStyle,
146 },
147 /// A sequence has ended.
148 ///
149 /// Matches the most recent [`Event::SequenceStart`] on the event stack.
150 SequenceEnd,
151 /// A block or flow mapping has started.
152 ///
153 /// Followed by alternating key/value node events (scalars or nested
154 /// collections), then a matching [`Event::MappingEnd`].
155 MappingStart {
156 /// The anchor name, if any (e.g. `&foo`).
157 anchor: Option<&'input str>,
158 /// Source span of the `&name` anchor token — from `&` through the last
159 /// byte of the name. `Some` when `anchor` is `Some`, `None` otherwise.
160 anchor_loc: Option<Span>,
161 /// The resolved tag, if any (e.g. `"tag:yaml.org,2002:map"` for `!!map`).
162 ///
163 /// See [`SequenceStart::tag`] for resolution semantics.
164 tag: Option<Cow<'input, str>>,
165 /// Source span of the tag token — from `!` through the last byte of the
166 /// tag token. `Some` when `tag` is `Some`, `None` otherwise.
167 tag_loc: Option<Span>,
168 /// Whether this is a block (indentation-based) or flow (`{...}`) mapping.
169 style: CollectionStyle,
170 },
171 /// A mapping has ended.
172 ///
173 /// Matches the most recent [`Event::MappingStart`] on the event stack.
174 MappingEnd,
175 /// A scalar value.
176 ///
177 /// `value` borrows from input when no transformation is required (the
178 /// vast majority of plain scalars). It owns when line folding produces
179 /// a string that doesn't exist contiguously in the input.
180 Scalar {
181 /// The scalar's decoded value.
182 value: Cow<'input, str>,
183 /// The style in which the scalar appeared in the source.
184 style: ScalarStyle,
185 /// The anchor name, if any (e.g. `&foo`).
186 anchor: Option<&'input str>,
187 /// Source span of the `&name` anchor token — from `&` through the last
188 /// byte of the name. `Some` when `anchor` is `Some`, `None` otherwise.
189 anchor_loc: Option<Span>,
190 /// The resolved tag, if any (e.g. `"tag:yaml.org,2002:str"` for `!!str`).
191 ///
192 /// See [`SequenceStart::tag`] for resolution semantics.
193 tag: Option<Cow<'input, str>>,
194 /// Source span of the tag token — from `!` through the last byte of the
195 /// tag token. `Some` when `tag` is `Some`, `None` otherwise.
196 tag_loc: Option<Span>,
197 },
198}