use crate::{
Delimiter, DelimiterValue, Lex, Parse, ParseStream, PrettyNode, PrettyTree, Spanned,
TokenParseError, TokenStream, parse2, token_stream::delim::parse_any_group,
};
#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
pub struct Delimited<S, D = Delimiter> {
pub delimiter: D,
pub contents: S,
}
#[macro_export]
macro_rules! paren {
($contents:expr, $span:expr $(,)?) => {
$crate::Delimited::new($crate::Delimiter, $contents)
};
($contents:ty) => {
$crate::Delimited<$contents, $crate::Delimiter![()]>
};
}
#[macro_export]
macro_rules! braces {
($contents:expr, $span:expr $(,)?) => {
$crate::Delimited::new($crate::Delimiter, $contents)
};
($contents:ty) => {
$crate::Delimited<$contents, $crate::Delimiter![{}]>
};
}
#[macro_export]
macro_rules! brackets {
($contents:expr, $span:expr $(,)?) => {
$crate::Delimited::new($crate::Delimiter![[]]($span), $contents)
};
($contents:ty) => {
$crate::Delimited<$contents, $crate::Delimiter![[]]>
};
}
#[macro_export]
macro_rules! angle_bars {
($contents:expr, $span:expr $(,)?) => {
$crate::Delimited::new($crate::Delimiter, $contents)
};
($contents:ty) => {
$crate::Delimited<$contents, $crate::Delimiter![<| |>]>
};
}
impl<S, D> Delimited<S, D> {
pub fn new(delimiter: D, contents: S) -> Self {
Self {
delimiter,
contents,
}
}
pub fn into_parts(self) -> (D, S) {
(self.delimiter, self.contents)
}
}
impl<S, D> Parse for Delimited<S, D>
where
S: Parse,
D: DelimiterValue,
{
fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
let group = parse_any_group(input, D::expected())?;
let raw_delimiter = group.delimiter().clone();
let delimiter = D::from_delimiter(raw_delimiter.clone()).ok_or_else(|| {
TokenParseError::unexpected(
D::expected(),
raw_delimiter.kind.opening(),
raw_delimiter.span(),
)
})?;
let contents = parse2(group.into_stream())?;
Ok(Self::new(delimiter, contents))
}
}
impl<S, D> Lex for Delimited<S, D>
where
S: Lex,
D: DelimiterValue,
{
fn to_tokens(&self, output: &mut TokenStream) {
self.delimiter
.surround(output, self.contents.to_token_stream());
}
}
impl<S, D> PrettyTree for Delimited<S, D>
where
S: PrettyTree + Spanned,
D: DelimiterValue,
{
fn pretty_tree(&self) -> PrettyNode {
let delimiter = self.delimiter.delimiter();
let mut node = PrettyNode::collection("Delimited", self.span());
node.push("contents", &self.contents);
node.push_node(
"delimiter",
PrettyNode::delimiter(delimiter.kind, delimiter.spans),
);
node
}
}
#[cfg(test)]
mod tests {
use super::Delimited;
use crate::{DelimiterKind, Lex, lex_str, parse2};
#[test]
fn arbitrary_delimiter_retains_each_family() {
for (source, expected) in [
("(+)", DelimiterKind::Parenthesis),
("[+]", DelimiterKind::Bracket),
("{+}", DelimiterKind::Brace),
("<|+|>", DelimiterKind::AngleBar),
] {
let parsed: Delimited<Token![+]> = parse2(lex_str(source).unwrap()).unwrap();
assert_eq!(parsed.delimiter.kind, expected);
assert_eq!(parsed.to_m2(), source);
}
}
}