use std::fmt::Display;
use unsynn::*;
use crate::parser::{Block, KBefore, KBiased, KIn, KUnbiased};
unsynn! {
enum Fragment {
After {
_before: KBefore,
_arrow: FatArrow,
block: Block,
},
Before {
_before: KBefore,
_arrow: FatArrow,
block: Block,
},
Block {
pattern: LazyVec<TokenTree, KIn>,
expr: LazyVec<TokenTree, Either<FatArrow, EndOfStream>>,
block: Block,
},
Expr {
pattern: LazyVec<TokenTree, KIn>,
expr: LazyVec<TokenTree, Either<FatArrow, EndOfStream>>,
},
Pattern {
_except: Except<KIn>,
pattern: LazyVec<TokenTree, KIn>,
}
}
enum Ast {
Unfinished {
_biasedness: Either<KBiased, KUnbiased>,
fragments: Vec<Fragment>,
},
MissingBiasedness {
_missing: Except<Either<KBiased, KUnbiased>>,
tokens: LazyVecUntil<TokenTree, EndOfStream>,
}
}
}
pub(crate) fn friendly_error<E: Display>(tokens: TokenStream, err: E) -> TokenStream {
let mut output = TokenStream::new();
let ast = Ast::parse(&mut tokens.to_token_iter()).expect("this parser should accept anything");
let mut before = None;
let mut after = None;
let mut suggest_before_after = false;
match ast {
Ast::Unfinished { _biasedness, fragments } => {
for fragment in fragments {
match fragment {
Fragment::Before { _before, _arrow, block } => before = Some(block),
Fragment::After { _before, _arrow, block } => after = Some(block),
Fragment::Block { pattern, expr, block } => {
let pattern = pattern.vec;
let expr = expr.vec;
output.extend(quote! {
if let #pattern = { #expr }.await {
#block
}
});
},
Fragment::Expr { pattern, expr } => {
let pattern = pattern.vec;
let expr = expr.vec;
output.extend(quote! {
if let #pattern = { #expr }.await {
}
});
},
Fragment::Pattern { _except, pattern } => {
suggest_before_after = true;
let pattern = pattern.vec;
output.extend(quote! {
if let #pattern = ::core::panic!() {
}
});
}
}
}
},
Ast::MissingBiasedness { _missing, tokens } => {
output.extend(quote! {
struct FloopHelper;
let biased = FloopHelper;
let unbiased = FloopHelper;
let biasedness: FloopHelper = #tokens;
});
}
}
let before_after_suggestion = suggest_before_after.then_some(quote! {
enum FloopHelper {
before,
after
}
use FloopHelper::*;
});
let err = format_literal_string!("{}", err);
quote! {
{
#before_after_suggestion
async {
loop {
#before
#output
#after
}
};
::core::compile_error!(#err)
}
}
}