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    opening_trivia: TrailingTrivia,
167    closing_trivia: TrailingTrivia,
168}
169
170impl Delimiter {
171    /// Creates type-erased delimiter data.
172    pub fn new(kind: DelimiterKind, spans: DoubleSpan) -> Self {
173        Self {
174            kind,
175            spans,
176            opening_trivia: TrailingTrivia::default(),
177            closing_trivia: TrailingTrivia::default(),
178        }
179    }
180
181    /// Returns the real span of the opening bracket.
182    pub fn opening_span(&self) -> Span {
183        self.spans.open()
184    }
185
186    /// Returns the real span of the closing bracket.
187    pub fn closing_span(&self) -> Option<Span> {
188        self.spans.close()
189    }
190
191    /// Reports whether the closing delimiter was present in source.
192    pub fn is_closed(&self) -> bool {
193        self.spans.is_closed()
194    }
195}
196
197impl Spanned for Delimiter {
198    fn try_span(&self) -> Option<Span> {
199        self.spans.try_span()
200    }
201}
202
203impl DelimiterValue for Delimiter {
204    fn from_delimiter(delimiter: Delimiter) -> Option<Self> {
205        Some(delimiter)
206    }
207
208    fn delimiter(&self) -> Delimiter {
209        self.clone()
210    }
211
212    fn expected() -> &'static str {
213        "a delimited group"
214    }
215
216    fn opening_trivia(&self) -> &TrailingTrivia {
217        &self.opening_trivia
218    }
219
220    fn opening_trivia_mut(&mut self) -> &mut TrailingTrivia {
221        &mut self.opening_trivia
222    }
223
224    fn closing_trivia(&self) -> &TrailingTrivia {
225        &self.closing_trivia
226    }
227
228    fn closing_trivia_mut(&mut self) -> &mut TrailingTrivia {
229        &mut self.closing_trivia
230    }
231}
232
233impl Parse for Delimiter {
234    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
235        let group = parse_any_group(input, Self::expected())?;
236        if !group.stream().is_empty() {
237            return Err(TokenParseError::unexpected(
238                "an empty delimited group",
239                group.delim_kind().opening(),
240                group.expect_span(),
241            ));
242        }
243        Ok(group.delimiter().clone())
244    }
245}
246
247impl Lex for Delimiter {
248    fn to_tokens(&self, output: &mut TokenStream) {
249        self.surround(output, TokenStream::new());
250    }
251}
252
253/// Parses one delimiter atom without any contained syntax.
254#[doc(hidden)]
255pub fn parse_delimiter<D: DelimiterToken>(input: &mut ParseStream) -> Result<D, TokenParseError> {
256    let kind = D::KIND;
257    let group = parse_group(input, kind)?;
258    if !group.stream().is_empty() {
259        return Err(TokenParseError::unexpected(
260            kind.opening(),
261            kind.opening(),
262            group.expect_span(),
263        ));
264    }
265    Ok(D::new(group.delimiter().spans.clone()))
266}
267
268/// Parses group.
269pub(crate) fn parse_group(
270    input: &mut ParseStream,
271    kind: DelimiterKind,
272) -> Result<TokenGroup, TokenParseError> {
273    let group = parse_any_group(input, kind.opening())?;
274    if group.delim_kind() != kind {
275        return Err(TokenParseError::unexpected(
276            kind.opening(),
277            group.delim_kind().opening(),
278            group.expect_span(),
279        ));
280    }
281    Ok(group)
282}
283
284/// Parses any group.
285pub(crate) fn parse_any_group(
286    input: &mut ParseStream,
287    expected: &'static str,
288) -> Result<TokenGroup, TokenParseError> {
289    let Some(token) = input.next_token() else {
290        return Err(TokenParseError::unexpected_end(expected, input.eof_span()));
291    };
292    let TokenTree::Group(group) = token else {
293        return Err(TokenParseError::unexpected_token(expected, &token));
294    };
295    Ok(group)
296}
297
298impl Display for Delimiter {
299    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
300        formatter.write_str(self.kind.opening())
301    }
302}
303impl Display for DelimiterKind {
304    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
305        formatter.write_str(self.opening())
306    }
307}
308
309impl DelimiterKind {
310    /// Returns the opening source spelling.
311    pub fn opening(self) -> &'static str {
312        match self {
313            Self::Parenthesis => "(",
314            Self::Bracket => "[",
315            Self::Brace => "{",
316            Self::AngleBar => "<|",
317        }
318    }
319
320    /// Returns the closing source spelling.
321    pub fn closing(self) -> &'static str {
322        match self {
323            Self::Parenthesis => ")",
324            Self::Bracket => "]",
325            Self::Brace => "}",
326            Self::AngleBar => "|>",
327        }
328    }
329}