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};
8
9use crate::{
10    Lex, Offset, Parse, ParseStream, Span, Spanned, TokenGroup, TokenParseError, TokenStream,
11    TokenTree,
12};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15/// The delimiter families recognized by raw syntax containers.
16///
17/// Every kind is spelled in the source and pairs an opening token with a
18/// closing one, so a group is opaque and its extent is read rather than
19/// inferred. Cell boundaries are deliberately absent: they are a parse
20/// result, not a delimiter.
21pub enum DelimiterKind {
22    /// `( ... )`.
23    Parenthesis,
24    /// `[ ... ]`.
25    Bracket,
26    /// `{ ... }`.
27    Brace,
28    /// `<| ... |>`.
29    AngleBar,
30}
31
32impl DelimiterKind {
33    /// Returns the expression family introduced by this delimiter.
34    pub const fn expression_name(self) -> &'static str {
35        match self {
36            Self::Parenthesis => "parenthesized expression",
37            Self::Bracket => "array expression",
38            Self::Brace => "list expression",
39            Self::AngleBar => "angle-bar list expression",
40        }
41    }
42}
43
44/// Delimiter data that can surround typed syntax.
45///
46/// The type-erased [`struct@Delimiter`] accepts every delimiter family. Generated
47/// [`DelimiterToken`] implementations refine it to one statically known family.
48pub trait DelimiterValue: Spanned + Lex + Sized {
49    /// Converts raw delimiter data into this representation.
50    fn from_delimiter(delimiter: Delimiter) -> Option<Self>;
51
52    /// Returns the type-erased delimiter data.
53    fn delimiter(&self) -> Delimiter;
54
55    /// Describes the accepted delimiter family in parse diagnostics.
56    fn expected() -> &'static str;
57
58    /// Emits `contents` surrounded by this delimiter.
59    fn surround(&self, output: &mut TokenStream, contents: TokenStream) {
60        output.extend([TokenGroup::new(self.delimiter(), contents)]);
61    }
62}
63
64/// A generated typed refinement of one raw delimiter kind.
65///
66/// Delimiter atoms are the container analogue of `Token![..]`: the typed CST
67/// stores the precise delimiter family, while [`TokenGroup`]
68/// carries the erased raw representation.
69pub trait DelimiterToken: Parse + DelimiterValue {
70    /// The raw delimiter family represented by this type.
71    const KIND: DelimiterKind;
72
73    /// Creates a typed delimiter from its two boundary spans.
74    fn new(spans: DoubleSpan) -> Self;
75
76    /// Returns the real opening and closing boundaries this atom was built
77    /// from, or a collapsed pair when it was constructed from one span.
78    fn spans(&self) -> DoubleSpan;
79}
80
81/// The real opening and closing boundaries of a paired delimiter.
82///
83/// A delimiter is two spelled tokens, not one span with an inferred width:
84/// storing both is what makes [`Delimiter::opening_span`] and
85/// [`Delimiter::closing_span`] plain field reads instead of arithmetic that
86/// assumes the source layout. `DoubleSpan(open, close)` mirrors
87/// `proc_macro2`'s open/close pair for a `Group`.
88#[derive(Debug, Clone, PartialEq, Eq, Default)]
89pub struct DoubleSpan(pub Span, pub Span);
90
91impl DoubleSpan {
92    /// Creates an opening and closing span pair.
93    pub fn new(open: Span, close: Span) -> Self {
94        Self(open, close)
95    }
96
97    /// A pair with no real boundaries, for synthetic or quoted delimiters
98    /// that were never lexed from source.
99    pub fn detached() -> Self {
100        Self(Span::detached(), Span::detached())
101    }
102
103    /// Creates a delimiter whose closing token is missing at `eof`.
104    pub fn unclosed(open: Span, eof: Offset) -> Self {
105        Self(open, Span::from_offset(eof))
106    }
107
108    /// Returns the opening delimiter span.
109    pub fn open(&self) -> Span {
110        self.0.clone()
111    }
112
113    /// Returns the closing delimiter span.
114    pub fn close(&self) -> Span {
115        self.1.clone()
116    }
117
118    /// Reports whether a closing delimiter was present or synthetically quoted.
119    pub fn is_closed(&self) -> bool {
120        self.1.bounds().is_none_or(|(start, end)| start != end)
121    }
122}
123
124impl Spanned for DoubleSpan {
125    fn span(&self) -> Span {
126        self.0.join(self.1.clone())
127    }
128}
129
130#[derive(Debug, Clone, PartialEq, Eq)]
131/// Type-erased delimiter data stored by a raw [`TokenGroup`].
132pub struct Delimiter {
133    /// The delimiter family.
134    pub kind: DelimiterKind,
135    /// The opening and closing source spans.
136    pub spans: DoubleSpan,
137}
138
139impl Delimiter {
140    /// Creates type-erased delimiter data.
141    pub fn new(kind: DelimiterKind, spans: DoubleSpan) -> Self {
142        Self { kind, spans }
143    }
144
145    /// Returns the real span of the opening bracket.
146    pub fn opening_span(&self) -> Span {
147        self.spans.open()
148    }
149
150    /// Returns the real span of the closing bracket.
151    pub fn closing_span(&self) -> Span {
152        self.spans.close()
153    }
154
155    /// Reports whether the closing delimiter was present in source.
156    pub fn is_closed(&self) -> bool {
157        self.spans.is_closed()
158    }
159}
160
161impl Spanned for Delimiter {
162    fn span(&self) -> Span {
163        self.spans.span()
164    }
165}
166
167impl DelimiterValue for Delimiter {
168    fn from_delimiter(delimiter: Delimiter) -> Option<Self> {
169        Some(delimiter)
170    }
171
172    fn delimiter(&self) -> Delimiter {
173        self.clone()
174    }
175
176    fn expected() -> &'static str {
177        "a delimited group"
178    }
179}
180
181impl Parse for Delimiter {
182    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
183        let group = parse_any_group(input, Self::expected())?;
184        if !group.stream().is_empty() {
185            return Err(TokenParseError::unexpected(
186                "an empty delimited group",
187                group.delim_kind().opening(),
188                group.span(),
189            ));
190        }
191        Ok(group.delimiter().clone())
192    }
193}
194
195impl Lex for Delimiter {
196    fn to_tokens(&self, output: &mut TokenStream) {
197        self.surround(output, TokenStream::new());
198    }
199}
200
201/// Parses one delimiter atom without any contained syntax.
202#[doc(hidden)]
203pub fn parse_delimiter<D: DelimiterToken>(input: &mut ParseStream) -> Result<D, TokenParseError> {
204    let kind = D::KIND;
205    let group = parse_group(input, kind)?;
206    if !group.stream().is_empty() {
207        return Err(TokenParseError::unexpected(
208            kind.opening(),
209            kind.opening(),
210            group.span(),
211        ));
212    }
213    Ok(D::new(group.delimiter().spans.clone()))
214}
215
216pub(crate) fn parse_group(
217    input: &mut ParseStream,
218    kind: DelimiterKind,
219) -> Result<TokenGroup, TokenParseError> {
220    let group = parse_any_group(input, kind.opening())?;
221    if group.delim_kind() != kind {
222        return Err(TokenParseError::unexpected(
223            kind.opening(),
224            group.delim_kind().opening(),
225            group.span(),
226        ));
227    }
228    Ok(group)
229}
230
231pub(crate) fn parse_any_group(
232    input: &mut ParseStream,
233    expected: &'static str,
234) -> Result<TokenGroup, TokenParseError> {
235    let Some(token) = input.next_token() else {
236        return Err(TokenParseError::unexpected_end(expected, input.eof_span()));
237    };
238    let TokenTree::Group(group) = token else {
239        return Err(TokenParseError::unexpected_token(expected, &token));
240    };
241    Ok(group)
242}
243
244impl Display for Delimiter {
245    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
246        formatter.write_str(self.kind.opening())
247    }
248}
249impl Display for DelimiterKind {
250    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
251        formatter.write_str(self.opening())
252    }
253}
254
255impl DelimiterKind {
256    /// Returns the opening source spelling.
257    pub fn opening(self) -> &'static str {
258        match self {
259            Self::Parenthesis => "(",
260            Self::Bracket => "[",
261            Self::Brace => "{",
262            Self::AngleBar => "<|",
263        }
264    }
265
266    /// Returns the closing source spelling.
267    pub fn closing(self) -> &'static str {
268        match self {
269            Self::Parenthesis => ")",
270            Self::Bracket => "]",
271            Self::Brace => "}",
272            Self::AngleBar => "|>",
273        }
274    }
275}