Skip to main content

m2_syn/parser/
delimited.rs

1//! Typed syntax contained by one of the six delimiter families.
2
3use crate::{
4    Delimiter, DelimiterValue, Lex, Parse, ParseStream, PrettyNode, PrettyTree, Spanned,
5    TokenParseError, TokenStream, parse2, token_stream::delim::parse_any_group,
6};
7
8/// Syntax contained by an arbitrary or statically known delimiter family.
9///
10/// With its default `D = Delimiter`, `Delimited<S>` accepts any delimiter
11/// family. Supply a [`crate::Delimiter!`] type, for example
12/// `Delimited<S, Delimiter![()]>`, when the family is statically known. The
13/// delimiter retains both boundary spans, while `contents` owns the syntax
14/// between them.
15///
16/// ```
17/// use m2_syn::{Span, Lex};
18///
19/// type ParenthesizedPlus = m2_syn::paren!(m2_syn::Token![+]);
20/// let value: ParenthesizedPlus = m2_syn::paren!(
21///     m2_syn::Token![+](Span::detached()),
22///     Span::detached(),
23/// );
24/// assert_eq!(value.to_m2(), "(+)");
25/// ```
26#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
27pub struct Delimited<S, D = Delimiter> {
28    /// The delimiter family and its exact opening and closing spans.
29    pub delimiter: D,
30    /// The syntax stored between the delimiter boundaries.
31    pub contents: S,
32}
33
34/// Names or constructs parenthesized syntax.
35///
36/// `paren!(T)` is `Delimited<T, Delimiter![()]>`. The constructor form is
37/// `paren!(value, span)` where `span` describes the complete parenthesized value.
38#[macro_export]
39macro_rules! paren {
40    ($contents:expr, $span:expr $(,)?) => {
41        $crate::Delimited::new($crate::Delimiter![()]($span), $contents)
42    };
43    ($contents:ty) => {
44        $crate::Delimited<$contents, $crate::Delimiter![()]>
45    };
46}
47
48/// Names or constructs brace-delimited syntax.
49///
50/// Use `braces!(T)` as a type and `braces!(value, spans)` as a constructor.
51#[macro_export]
52macro_rules! braces {
53    ($contents:expr, $span:expr $(,)?) => {
54        $crate::Delimited::new($crate::Delimiter![{}]($span), $contents)
55    };
56    ($contents:ty) => {
57        $crate::Delimited<$contents, $crate::Delimiter![{}]>
58    };
59}
60
61/// Names or constructs bracket-delimited syntax.
62///
63/// Use `brackets!(T)` as a type and `brackets!(value, spans)` as a constructor.
64#[macro_export]
65macro_rules! brackets {
66    ($contents:expr, $span:expr $(,)?) => {
67        $crate::Delimited::new($crate::Delimiter![[]]($span), $contents)
68    };
69    ($contents:ty) => {
70        $crate::Delimited<$contents, $crate::Delimiter![[]]>
71    };
72}
73
74/// Names or constructs angle-bar-delimited syntax.
75///
76/// Use `angle_bars!(T)` as a type and `angle_bars!(value, spans)` as a
77/// constructor.
78#[macro_export]
79macro_rules! angle_bars {
80    ($contents:expr, $span:expr $(,)?) => {
81        $crate::Delimited::new($crate::Delimiter![<| |>]($span), $contents)
82    };
83    ($contents:ty) => {
84        $crate::Delimited<$contents, $crate::Delimiter![<| |>]>
85    };
86}
87
88impl<S, D> Delimited<S, D> {
89    /// Creates a delimited value from its delimiter and contents.
90    pub fn new(delimiter: D, contents: S) -> Self {
91        Self {
92            delimiter,
93            contents,
94        }
95    }
96
97    /// Separates the delimiter from the contained syntax.
98    pub fn into_parts(self) -> (D, S) {
99        (self.delimiter, self.contents)
100    }
101}
102
103impl<S, D> Parse for Delimited<S, D>
104where
105    S: Parse,
106    D: DelimiterValue,
107{
108    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
109        let group = parse_any_group(input, D::expected())?;
110        let raw_delimiter = group.delimiter().clone();
111        let delimiter = D::from_delimiter(raw_delimiter.clone()).ok_or_else(|| {
112            TokenParseError::unexpected(
113                D::expected(),
114                raw_delimiter.kind.opening(),
115                raw_delimiter.span(),
116            )
117        })?;
118        let contents = parse2(group.into_stream())?;
119        Ok(Self::new(delimiter, contents))
120    }
121}
122
123impl<S, D> Lex for Delimited<S, D>
124where
125    S: Lex,
126    D: DelimiterValue,
127{
128    fn to_tokens(&self, output: &mut TokenStream) {
129        self.delimiter
130            .surround(output, self.contents.to_token_stream());
131    }
132}
133
134impl<S, D> PrettyTree for Delimited<S, D>
135where
136    S: PrettyTree + Spanned,
137    D: DelimiterValue,
138{
139    fn pretty_tree(&self) -> PrettyNode {
140        let delimiter = self.delimiter.delimiter();
141        let mut node = PrettyNode::collection("Delimited", self.span());
142        node.push("contents", &self.contents);
143        node.push_node(
144            "delimiter",
145            PrettyNode::delimiter(delimiter.kind, delimiter.spans),
146        );
147        node
148    }
149}
150
151#[cfg(test)]
152mod tests {
153    use super::Delimited;
154    use crate::{DelimiterKind, Lex, lex_str, parse2};
155
156    #[test]
157    fn arbitrary_delimiter_retains_each_family() {
158        for (source, expected) in [
159            ("(+)", DelimiterKind::Parenthesis),
160            ("[+]", DelimiterKind::Bracket),
161            ("{+}", DelimiterKind::Brace),
162            ("<|+|>", DelimiterKind::AngleBar),
163        ] {
164            let parsed: Delimited<Token![+]> = parse2(lex_str(source).unwrap()).unwrap();
165            assert_eq!(parsed.delimiter.kind, expected);
166            assert_eq!(parsed.to_m2(), source);
167        }
168    }
169}