use quote::ToTokens as _;
use syn::{parse::ParseStream, Token};
use crate::util::debug_trace;
pub trait NeedsCommaAsArmBody {
fn needs_comma(&self) -> bool;
}
impl NeedsCommaAsArmBody for syn::Expr {
fn needs_comma(&self) -> bool {
#[allow(
clippy::enum_glob_use,
reason = "way too much repetition for this one..."
)]
use syn::Expr::*;
match self {
If(_) | Match(_) | Block(_) | Unsafe(_) | While(_) | Loop(_) | ForLoop(_)
| TryBlock(_) | Const(_) => false,
Array(_) | Assign(_) | Async(_) | Await(_) | Binary(_) | Break(_) | Call(_)
| Cast(_) | Closure(_) | Continue(_) | Field(_) | Group(_) | Index(_) | Infer(_)
| Let(_) | Lit(_) | Macro(_) | MethodCall(_) | Paren(_) | Path(_) | Range(_)
| RawAddr(_) | Reference(_) | Repeat(_) | Return(_) | Struct(_) | Try(_) | Tuple(_)
| Unary(_) | Yield(_) | Verbatim(_) => true,
_ => panic!(
"unsupported expression type (NeedsComma check): {}",
self.to_token_stream()
),
}
}
}
pub fn parse_tokens(input: ParseStream<'_>) -> syn::Result<proc_macro2::TokenStream> {
use proc_macro2::{Delimiter, TokenTree};
let mut collected = Vec::<TokenTree>::new();
while !input.is_empty() {
if input.peek(Token![,]) {
break;
}
let tt: TokenTree = input.parse()?;
match &tt {
TokenTree::Group(group) => {
let delim = group.delimiter();
debug_trace!("parsed group: {tt}");
collected.push(tt.clone());
if matches!(
delim,
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace
) {
if !expr_continues(input) {
break;
}
}
continue;
}
_ => {
debug_trace!("parsed: {tt}");
}
}
collected.push(tt);
}
Ok(collected.into_iter().collect())
}
fn expr_continues(input: ParseStream<'_>) -> bool {
if input.peek(Token![.]) || input.peek(Token![?]) {
return true;
}
if input.peek(syn::token::Paren) || input.peek(syn::token::Bracket) {
return true;
}
if input.peek(syn::token::Brace) || input.peek(syn::token::Lt) || input.peek(syn::token::Gt) {
return true;
}
if input.peek(Token![::]) {
return true;
}
if input.peek(Token![as]) {
return true;
}
false
}