Skip to main content

m2_syn/lex/token_stream/
delim.rs

1//! Raw and typed delimiter support.
2//!
3//! [`Delimiter`] is stored by raw [`TokenGroup`] token trees. Generated
4//! `Delimiter![..]` atoms implement [`DelimiterToken`] and are stored on typed
5//! delimited nodes, so flattening can recover the corresponding raw group.
6
7use std::fmt::{Display, Formatter};
8use std::ops::Bound;
9
10use crate::{
11    Lex, Parse, ParseStream, Span, Spanned, TokenGroup, TokenParseError, TokenStream, TokenTree,
12    TrailingTrivia,
13};
14use these_macros_should_be_illegal::discriminated_str;
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
16/// The delimiter families recognized by raw syntax containers.
17///
18/// Every kind is spelled in the source and pairs an opening token with a
19/// closing one, so a group is opaque and its extent is read rather than
20/// inferred. Cell boundaries are deliberately absent: they are a parse
21/// result, not a delimiter.
22#[discriminated_str(expression_name)]
23pub enum DelimiterKind {
24    /// `( ... )`.
25    Parenthesis = "parenthesized expression",
26    /// `[ ... ]`.
27    Bracket = "array expression",
28    /// `{ ... }`.
29    Brace = "list expression",
30    /// `<| ... |>`.
31    AngleBar = "angle-bar list expression",
32}
33
34/// Delimiter data that can surround typed syntax.
35///
36/// The type-erased [`struct@Delimiter`] accepts every delimiter family. Generated
37/// [`DelimiterToken`] implementations refine it to one statically known family.
38pub trait DelimiterValue: Spanned + Lex + Sized {
39    /// Converts raw delimiter data into this representation.
40    fn from_delimiter(delimiter: Delimiter) -> Option<Self>;
41
42    /// Returns the type-erased delimiter data.
43    fn delimiter(&self) -> Delimiter;
44
45    /// Describes the accepted delimiter family in parse diagnostics.
46    fn expected() -> &'static str;
47
48    /// Borrows the non-space trivia following the opening delimiter.
49    fn opening_trivia(&self) -> &TrailingTrivia;
50
51    /// Mutably borrows the non-space trivia following the opening delimiter.
52    fn opening_trivia_mut(&mut self) -> &mut TrailingTrivia;
53
54    /// Borrows the non-space trivia following the closing delimiter.
55    fn closing_trivia(&self) -> &TrailingTrivia;
56
57    /// Mutably borrows the non-space trivia following the closing delimiter.
58    fn closing_trivia_mut(&mut self) -> &mut TrailingTrivia;
59
60    /// Emits `contents` surrounded by this delimiter.
61    fn surround(&self, output: &mut TokenStream, contents: TokenStream) {
62        let mut grouped = TokenStream::new();
63        self.opening_trivia().to_tokens(&mut grouped);
64        contents.to_tokens(&mut grouped);
65        output.extend([TokenGroup::new(self.delimiter(), grouped)]);
66        self.closing_trivia().to_tokens(output);
67    }
68}
69
70/// A generated typed refinement of one raw delimiter kind.
71///
72/// Delimiter atoms are the container analogue of `Token![..]`: the typed CST
73/// stores the precise delimiter family, while [`TokenGroup`]
74/// carries the erased raw representation.
75pub trait DelimiterToken: Parse + DelimiterValue {
76    /// The raw delimiter family represented by this type.
77    const KIND: DelimiterKind;
78
79    /// Creates a typed delimiter from its two boundary spans.
80    fn new(spans: DoubleSpan) -> Self;
81
82    /// Returns the real opening and closing boundaries this atom was built
83    /// from, or a collapsed pair when it was constructed from one span.
84    fn spans(&self) -> DoubleSpan;
85}
86
87/// The source boundaries of a complete or incomplete delimiter pair.
88///
89/// A delimiter is two spelled tokens, not one span with an inferred width:
90/// storing both is what makes [`Delimiter::opening_span`] and
91/// [`Delimiter::closing_span`] plain field reads instead of arithmetic that
92/// assumes the source layout. The closing boundary is [`Bound::Unbounded`]
93/// while the group is incomplete, so a missing token is never confused with
94/// a zero-width token at the current end of input.
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub struct DoubleSpan(pub Span, pub Bound<Span>);
97
98impl DoubleSpan {
99    /// Creates an opening and closing span pair.
100    pub fn new(open: Span, close: Span) -> Self {
101        Self(open, Bound::Included(close))
102    }
103
104    /// Creates a pair backed by the delimiter's synthetic source spelling.
105    pub fn synthetic(kind: DelimiterKind) -> Self {
106        let spelling = format!("{}{}", kind.opening(), kind.closing());
107        let span = Span::for_text(spelling);
108        let boundary = kind.opening().len();
109        Self::new(
110            span.subspan(0, boundary),
111            span.subspan(boundary, span.len().unwrap_or(boundary)),
112        )
113    }
114
115    /// Creates a delimiter whose closing token is not present yet.
116    pub fn unclosed(open: Span) -> Self {
117        Self(open, Bound::Unbounded)
118    }
119
120    /// Returns the opening delimiter span.
121    pub fn open(&self) -> Span {
122        self.0.clone()
123    }
124
125    /// Returns the closing delimiter span when it is present.
126    pub fn close(&self) -> Option<Span> {
127        match &self.1 {
128            Bound::Included(span) | Bound::Excluded(span) => Some(span.clone()),
129            Bound::Unbounded => None,
130        }
131    }
132
133    /// Returns the closing boundary, preserving an incomplete delimiter as
134    /// [`Bound::Unbounded`].
135    pub fn close_bound(&self) -> Bound<Span> {
136        self.1.clone()
137    }
138
139    /// Records the closing token of an incomplete delimiter pair.
140    pub(crate) fn complete(&mut self, close: Span) {
141        debug_assert!(matches!(self.1, Bound::Unbounded));
142        self.1 = Bound::Included(close);
143    }
144
145    /// Reports whether a closing delimiter was present or synthetically quoted.
146    pub fn is_closed(&self) -> bool {
147        !matches!(self.1, Bound::Unbounded)
148    }
149}
150
151impl Spanned for DoubleSpan {
152    fn try_span(&self) -> Option<Span> {
153        self.close()
154            .and_then(|close| self.0.join(close))
155            .or_else(|| Some(self.0.clone()))
156    }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
160/// Type-erased delimiter data stored by a raw [`TokenGroup`].
161pub struct Delimiter {
162    /// The delimiter family.
163    pub kind: DelimiterKind,
164    /// The opening and closing source spans.
165    pub spans: DoubleSpan,
166    /// The opening trivia.
167    opening_trivia: TrailingTrivia,
168    /// The closing trivia.
169    closing_trivia: TrailingTrivia,
170}
171
172impl Delimiter {
173    /// Creates type-erased delimiter data.
174    pub fn new(kind: DelimiterKind, spans: DoubleSpan) -> Self {
175        Self {
176            kind,
177            spans,
178            opening_trivia: TrailingTrivia::default(),
179            closing_trivia: TrailingTrivia::default(),
180        }
181    }
182
183    /// Returns the real span of the opening bracket.
184    pub fn opening_span(&self) -> Span {
185        self.spans.open()
186    }
187
188    /// Returns the real span of the closing bracket.
189    pub fn closing_span(&self) -> Option<Span> {
190        self.spans.close()
191    }
192
193    /// Reports whether the closing delimiter was present in source.
194    pub fn is_closed(&self) -> bool {
195        self.spans.is_closed()
196    }
197}
198
199impl Spanned for Delimiter {
200    fn try_span(&self) -> Option<Span> {
201        self.spans.try_span()
202    }
203}
204
205impl DelimiterValue for Delimiter {
206    fn from_delimiter(delimiter: Delimiter) -> Option<Self> {
207        Some(delimiter)
208    }
209
210    fn delimiter(&self) -> Delimiter {
211        self.clone()
212    }
213
214    fn expected() -> &'static str {
215        "a delimited group"
216    }
217
218    fn opening_trivia(&self) -> &TrailingTrivia {
219        &self.opening_trivia
220    }
221
222    fn opening_trivia_mut(&mut self) -> &mut TrailingTrivia {
223        &mut self.opening_trivia
224    }
225
226    fn closing_trivia(&self) -> &TrailingTrivia {
227        &self.closing_trivia
228    }
229
230    fn closing_trivia_mut(&mut self) -> &mut TrailingTrivia {
231        &mut self.closing_trivia
232    }
233}
234
235impl Parse for Delimiter {
236    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
237        let group = parse_any_group(input, Self::expected())?;
238        if !group.stream().is_empty() {
239            return Err(TokenParseError::unexpected(
240                "an empty delimited group",
241                group.delim_kind().opening(),
242                group.expect_span(),
243            ));
244        }
245        Ok(group.delimiter().clone())
246    }
247}
248
249impl Lex for Delimiter {
250    fn to_tokens(&self, output: &mut TokenStream) {
251        self.surround(output, TokenStream::new());
252    }
253}
254
255/// Parses one delimiter atom without any contained syntax.
256#[doc(hidden)]
257pub fn parse_delimiter<D: DelimiterToken>(input: &mut ParseStream) -> Result<D, TokenParseError> {
258    let kind = D::KIND;
259    let group = parse_group(input, kind)?;
260    if !group.stream().is_empty() {
261        return Err(TokenParseError::unexpected(
262            kind.opening(),
263            kind.opening(),
264            group.expect_span(),
265        ));
266    }
267    Ok(D::new(group.delimiter().spans.clone()))
268}
269
270/// Parses group.
271pub(crate) fn parse_group(
272    input: &mut ParseStream,
273    kind: DelimiterKind,
274) -> Result<TokenGroup, TokenParseError> {
275    let group = parse_any_group(input, kind.opening())?;
276    if group.delim_kind() != kind {
277        return Err(TokenParseError::unexpected(
278            kind.opening(),
279            group.delim_kind().opening(),
280            group.expect_span(),
281        ));
282    }
283    Ok(group)
284}
285
286/// Parses any group.
287pub(crate) fn parse_any_group(
288    input: &mut ParseStream,
289    expected: &'static str,
290) -> Result<TokenGroup, TokenParseError> {
291    let Some(token) = input.next_token() else {
292        return Err(TokenParseError::unexpected_end(expected, input.eof_span()));
293    };
294    let TokenTree::Group(group) = token else {
295        return Err(TokenParseError::unexpected_token(expected, &token));
296    };
297    Ok(group)
298}
299
300impl Display for Delimiter {
301    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
302        formatter.write_str(self.kind.opening())
303    }
304}
305impl Display for DelimiterKind {
306    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
307        formatter.write_str(self.opening())
308    }
309}
310
311impl DelimiterKind {
312    /// Returns the opening source spelling.
313    pub fn opening(self) -> &'static str {
314        match self {
315            Self::Parenthesis => "(",
316            Self::Bracket => "[",
317            Self::Brace => "{",
318            Self::AngleBar => "<|",
319        }
320    }
321
322    /// Returns the closing source spelling.
323    pub fn closing(self) -> &'static str {
324        match self {
325            Self::Parenthesis => ")",
326            Self::Bracket => "]",
327            Self::Brace => "}",
328            Self::AngleBar => "|>",
329        }
330    }
331}