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