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