Skip to main content

moxy_token/
group.rs

1use crate::lex::{Cursor, LexError, Scan};
2use crate::span::DelimSpan;
3use crate::{Delim, Span, TokenStream, TokenTree};
4
5/// A delimited sequence of token trees.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct Group {
8    pub delim: Delim,
9    pub span: DelimSpan,
10    pub tokens: TokenStream,
11}
12
13impl Group {
14    #[inline]
15    pub fn new(delim: Delim, stream: TokenStream) -> Self {
16        let content_span = stream.span();
17        let span = if content_span.is_empty() {
18            DelimSpan::new(Span::call_site(), Span::call_site())
19        } else {
20            DelimSpan::new(content_span, content_span)
21        };
22
23        Self {
24            delim,
25            span,
26            tokens: stream,
27        }
28    }
29
30    #[inline]
31    pub fn to_token_tree(&self) -> TokenTree {
32        TokenTree::Group(self.clone())
33    }
34
35    #[inline]
36    pub fn into_token_tree(self) -> TokenTree {
37        TokenTree::Group(self)
38    }
39}
40
41impl std::fmt::Display for Group {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        match self.delim {
44            Delim::None => write!(f, "{}", self.tokens),
45            d => write!(f, "{}{}{}", d.open(), self.tokens, d.close()),
46        }
47    }
48}
49
50impl Scan for Group {
51    fn scan(cursor: Cursor<'_>) -> Result<(Cursor<'_>, Self), LexError> {
52        let ch = cursor.first().ok_or(cursor.error())?;
53        let delim = Delim::from_open(ch).ok_or(cursor.error())?;
54        let c = cursor.advance_by(ch.len_utf8());
55        let (c, inner) = TokenStream::scan(c)?;
56        let close_ch = c
57            .first()
58            .ok_or_else(|| cursor.error().message(format!("unclosed delimiter '{}'", delim.open())))?;
59
60        let close_delim = Delim::from_close(close_ch).ok_or_else(|| {
61            c.error()
62                .message(format!("expected '{}', found '{}'", delim.close(), close_ch))
63        })?;
64
65        if delim != close_delim {
66            return Err(c.error().message(format!(
67                "mismatched delimiter: expected '{}', found '{}'",
68                delim.close(),
69                close_ch,
70            )));
71        }
72
73        let c = c.advance_by(close_ch.len_utf8());
74        let mut group = Self::new(delim, inner);
75        group.span = DelimSpan::new(cursor.span(), c.span());
76
77        Ok((c, group))
78    }
79}
80
81impl crate::ToTokens for Group {
82    fn to_tokens(&self, tokens: &mut crate::TokenStream) {
83        tokens.extend_one(crate::TokenTree::Group(self.clone()));
84    }
85}
86
87impl crate::Spanner for Group {
88    fn span(&self) -> Span {
89        self.span.span()
90    }
91}
92
93#[cfg(feature = "serde")]
94impl serde::Serialize for Group {
95    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
96    where
97        S: serde::Serializer,
98    {
99        use serde::ser::SerializeStruct;
100
101        let mut o = s.serialize_struct("Group", 2)?;
102        o.serialize_field("delim", &self.delim)?;
103        o.serialize_field("tokens", &self.tokens)?;
104        o.end()
105    }
106}