use core::slice;
use crate::alloc::vec;
use crate::ast::prelude::*;
#[test]
#[cfg(not(miri))]
fn ast_parse() {
rt::<ast::Parenthesized<ast::Expr, T![,]>>("(1, \"two\")");
rt::<ast::Parenthesized<ast::Expr, T![,]>>("(1, 2,)");
rt::<ast::Parenthesized<ast::Expr, T![,]>>("(1, 2, foo())");
rt::<ast::Bracketed<ast::Expr, T![,]>>("[1, \"two\"]");
rt::<ast::Bracketed<ast::Expr, T![,]>>("[1, 2,]");
rt::<ast::Bracketed<ast::Expr, T![,]>>("[1, 2, foo()]");
rt::<ast::Braced<ast::Expr, T![,]>>("{1, \"two\"}");
rt::<ast::Braced<ast::Expr, T![,]>>("{1, 2,}");
rt::<ast::Braced<ast::Expr, T![,]>>("{1, 2, foo()}");
rt::<ast::AngleBracketed<ast::Path, T![,]>>("<Foo, Bar>");
rt::<ast::AngleBracketed<ast::PathSegmentExpr, T![,]>>("<1, \"two\">");
rt::<ast::AngleBracketed<ast::PathSegmentExpr, T![,]>>("<1, 2,>");
rt::<ast::AngleBracketed<ast::PathSegmentExpr, T![,]>>("<1, 2, foo()>");
}
macro_rules! grouped {
($(#[$meta:meta])* $name:ident { $field:ident, $open:ty, $close:ty }) => {
$(#[$meta])*
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens)]
#[try_clone(bound = {T: TryClone, S: TryClone})]
#[non_exhaustive]
pub struct $name<T, S> {
pub open: $open,
pub $field: Vec<(T, Option<S>)>,
pub close: $close,
}
impl<T, S> Spanned for $name<T, S> {
#[inline]
fn span(&self) -> Span {
self.open.span().join(self.close.span())
}
}
impl<T, S> $name<T, S> {
pub fn is_empty(&self) -> bool {
self.$field.is_empty()
}
pub fn len(&self) -> usize {
self.$field.len()
}
pub fn first(&self) -> Option<&(T, Option<S>)> {
self.$field.first()
}
pub fn last(&self) -> Option<&(T, Option<S>)> {
self.$field.last()
}
pub fn iter(&self) -> slice::Iter<'_, (T, Option<S>)> {
self.$field.iter()
}
pub fn iter_mut(&mut self) -> slice::IterMut<'_, (T, Option<S>)> {
self.$field.iter_mut()
}
pub fn as_slice(&self) -> &[(T, Option<S>)] {
&*self.$field
}
pub fn as_mut(&mut self) -> &mut [(T, Option<S>)] {
&mut *self.$field
}
#[allow(unused)]
pub(crate) fn drain(&mut self) -> impl Iterator<Item = (T, Option<S>)> + '_ {
self.$field.drain(..)
}
}
impl<'a, T, S> IntoIterator for &'a $name<T, S> {
type Item = &'a (T, Option<S>);
type IntoIter = slice::Iter<'a, (T, Option<S>)>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T, S> IntoIterator for &'a mut $name<T, S> {
type Item = &'a mut (T, Option<S>);
type IntoIter = slice::IterMut<'a, (T, Option<S>)>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T, S> IntoIterator for $name<T, S> {
type Item = (T, Option<S>);
type IntoIter = vec::IntoIter<(T, Option<S>)>;
fn into_iter(self) -> Self::IntoIter {
self.$field.into_iter()
}
}
impl<T, S> $name<T, S>
where
T: Parse,
S: Peek + Parse,
{
pub fn parse_from_first(
parser: &mut Parser<'_>,
open: $open,
mut current: T,
) -> Result<Self> {
let mut $field = Vec::new();
loop {
let comma = parser.parse::<Option<S>>()?;
let is_end = comma.is_none();
$field.try_push((current, comma))?;
if is_end || parser.peek::<$close>()? {
break;
}
current = parser.parse()?;
}
let close = parser.parse()?;
Ok(Self {
open,
$field,
close,
})
}
}
impl<T, S> Parse for $name<T, S>
where
T: Parse,
S: Peek + Parse,
{
fn parse(parser: &mut Parser<'_>) -> Result<Self> {
let open = parser.parse()?;
let mut $field = Vec::new();
while !parser.peek::<$close>()? {
let expr = parser.parse()?;
let sep = parser.parse::<Option<S>>()?;
let is_end = sep.is_none();
$field.try_push((expr, sep))?;
if is_end {
break;
}
}
let close = parser.parse()?;
Ok(Self {
open,
$field,
close,
})
}
}
impl<T, S> Peek for $name<T, S> {
fn peek(p: &mut Peeker<'_>) -> bool {
<$open>::peek(p)
}
}
}
}
grouped! {
Parenthesized { parenthesized, ast::OpenParen, ast::CloseParen }
}
grouped! {
Bracketed { bracketed, ast::OpenBracket, ast::CloseBracket }
}
grouped! {
Braced { braced, ast::OpenBrace, ast::CloseBrace }
}
grouped! {
AngleBracketed { angle_bracketed, ast::generated::Lt, ast::generated::Gt }
}