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