Skip to main content

yaml_rt_core/
syntax.rs

1use crate::semantic::SemanticStore;
2use crate::{NodeId, Parser, Source, Span, YamlError};
3
4/// Lossless syntax node produced by the CST parser.
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct Node {
7    /// Node classification.
8    pub(crate) kind: NodeKind,
9    pub(crate) syntax_flags: u8,
10    /// Original source span for this node.
11    pub(crate) span: Span,
12    pub(crate) parent: u32,
13    pub(crate) first_child: u32,
14    pub(crate) last_child: u32,
15    pub(crate) next_sibling: u32,
16    pub(crate) semantic: u32,
17}
18
19pub(crate) const NO_NODE: u32 = u32::MAX;
20pub(crate) const NO_SEMANTIC_NODE: u32 = u32::MAX;
21pub(crate) const COMMON_SEMANTIC_NODE: u32 = u32::MAX - 1;
22pub(crate) const NODE_SEMANTIC_ALIAS: u8 = 1 << 3;
23pub(crate) const NODE_EXPLICIT_START: u8 = 1 << 4;
24pub(crate) const NODE_EXPLICIT_END: u8 = 1 << 5;
25pub(crate) const NODE_SCALAR_STYLE_MASK: u8 = 0b11;
26pub(crate) const NODE_SCALAR_PLAIN: u8 = 1;
27pub(crate) const NODE_SCALAR_SINGLE_QUOTED: u8 = 2;
28pub(crate) const NODE_SCALAR_DOUBLE_QUOTED: u8 = 3;
29pub(crate) const NODE_SCALAR_SYNTAX_VALIDATED: u8 = 1 << 2;
30
31impl Node {
32    /// Returns this node's syntax classification.
33    #[must_use]
34    pub const fn kind(&self) -> NodeKind {
35        self.kind
36    }
37
38    /// Returns this node's original source span.
39    #[must_use]
40    pub const fn span(&self) -> Span {
41        self.span
42    }
43
44    /// Returns this node's parent, when it is not the stream root.
45    #[must_use]
46    pub const fn parent(&self) -> Option<NodeId> {
47        node_link(self.parent)
48    }
49}
50
51/// Iterator over a node's children in source order.
52#[derive(Debug, Clone)]
53pub struct Children<'doc> {
54    nodes: &'doc [Node],
55    next: u32,
56}
57
58impl<'doc> Children<'doc> {
59    pub(crate) fn new(nodes: &'doc [Node], parent: NodeId) -> Self {
60        let next = nodes
61            .get(parent.as_usize())
62            .map_or(NO_NODE, |node| node.first_child);
63        Self { nodes, next }
64    }
65}
66
67impl Iterator for Children<'_> {
68    type Item = NodeId;
69
70    fn next(&mut self) -> Option<Self::Item> {
71        let id = node_link(self.next)?;
72        self.next = self.nodes[id.as_usize()].next_sibling;
73        Some(id)
74    }
75}
76
77pub(crate) const fn node_link(link: u32) -> Option<NodeId> {
78    if link == NO_NODE {
79        None
80    } else {
81        Some(NodeId(link))
82    }
83}
84
85/// Node kinds emitted by the CST parser.
86#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
87pub enum NodeKind {
88    /// Complete YAML stream.
89    Stream,
90    /// Content document inside a stream.
91    Document,
92    /// Explicit document start or end marker.
93    DocumentMarker,
94    /// YAML directive line.
95    Directive,
96    /// Block mapping collection.
97    BlockMapping,
98    /// One mapping entry line.
99    MappingEntry,
100    /// Block sequence collection.
101    BlockSequence,
102    /// One block or flow sequence item wrapper.
103    SequenceEntry,
104    /// Single-line flow sequence collection.
105    FlowSequence,
106    /// Single-line flow mapping collection.
107    FlowMapping,
108    /// Literal block scalar collection.
109    LiteralScalar,
110    /// Folded block scalar collection.
111    FoldedScalar,
112    /// Scalar syntax span.
113    Scalar,
114}
115
116/// Semantic YAML event produced by the parser.
117#[derive(Debug, Clone, PartialEq, Eq)]
118pub struct YamlEvent {
119    /// Event classification.
120    pub kind: YamlEventKind,
121    /// Source span associated with this event.
122    pub span: Span,
123    /// CST node that originated this semantic event, when applicable.
124    pub(crate) cst: Option<NodeId>,
125    pub(crate) content_indent: Option<u32>,
126}
127
128/// YAML collection spelling.
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum CollectionStyle {
131    /// Block collection syntax.
132    Block,
133    /// Flow collection syntax.
134    Flow,
135}
136
137/// YAML scalar spelling.
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum YamlScalarStyle {
140    /// Plain scalar syntax.
141    Plain,
142    /// Single-quoted scalar syntax.
143    SingleQuoted,
144    /// Double-quoted scalar syntax.
145    DoubleQuoted,
146    /// Literal block scalar syntax.
147    Literal,
148    /// Folded block scalar syntax.
149    Folded,
150}
151
152/// Semantic YAML event kinds.
153#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum YamlEventKind {
155    /// Start of a YAML stream.
156    StreamStart,
157    /// End of a YAML stream.
158    StreamEnd,
159    /// Start of a YAML document.
160    DocumentStart {
161        /// Whether the source used an explicit `---` marker.
162        explicit: bool,
163    },
164    /// End of a YAML document.
165    DocumentEnd {
166        /// Whether the source used an explicit `...` marker.
167        explicit: bool,
168    },
169    /// Start of a sequence node.
170    SequenceStart {
171        /// Sequence spelling style.
172        style: CollectionStyle,
173        /// Explicit tag, when present.
174        tag: Option<String>,
175        /// Explicit anchor, when present.
176        anchor: Option<String>,
177    },
178    /// End of a sequence node.
179    SequenceEnd,
180    /// Start of a mapping node.
181    MappingStart {
182        /// Mapping spelling style.
183        style: CollectionStyle,
184        /// Explicit tag, when present.
185        tag: Option<String>,
186        /// Explicit anchor, when present.
187        anchor: Option<String>,
188    },
189    /// End of a mapping node.
190    MappingEnd,
191    /// Scalar node with decoded content.
192    Scalar {
193        /// Scalar spelling style.
194        style: YamlScalarStyle,
195        /// Decoded scalar value.
196        value: String,
197        /// Explicit tag, when present.
198        tag: Option<String>,
199        /// Explicit anchor, when present.
200        anchor: Option<String>,
201    },
202    /// Alias node.
203    Alias {
204        /// Alias name without the leading `*`.
205        name: String,
206    },
207}
208
209/// Parses a source buffer into a lossless CST node arena.
210///
211/// # Errors
212///
213/// Returns an error when the source contains YAML syntax the parser cannot
214/// accept or when parser events cannot be produced from the CST.
215pub fn parse_cst(source: &Source) -> Result<Vec<Node>, YamlError> {
216    Parser::new(source).parse().map(|parsed| parsed.nodes)
217}
218
219#[derive(Debug, Clone, PartialEq, Eq)]
220pub(crate) struct ParsedYaml {
221    pub(crate) nodes: Vec<Node>,
222    pub(crate) semantics: SemanticStore,
223}