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