use proc_macro::{Delimiter, Group, Ident, TokenStream, TokenTree};
use super::{
eval::Eval,
util::{is_comma, must_be_assign, must_be_comma, next_token},
};
pub(crate) fn run(input: TokenStream) -> TokenStream {
let mut iter = input.into_iter();
let tt = next_token(&mut iter);
let eval_success = eval(tt, &mut iter);
let mut result_ok = Vec::<TokenTree>::new();
let mut result_nok = Vec::<TokenTree>::new();
let mut first_arm = true;
loop {
let next_token = iter.next();
match next_token {
Some(tt) => match tt {
TokenTree::Punct(punct) => match punct.as_char() {
',' => match first_arm {
true => first_arm = false,
false => panic!("Tertiary evaluation arm not supported"),
},
_ => match first_arm {
true => result_ok.push(TokenTree::Punct(punct)),
false => result_nok.push(TokenTree::Punct(punct)),
},
},
_ => match first_arm {
true => result_ok.push(tt),
false => result_nok.push(tt),
},
},
None => break,
}
}
match eval_success {
true => result_ok.into_iter().collect(),
false => result_nok.into_iter().collect(),
}
}
fn eval(mut tt: TokenTree, iter: &mut proc_macro::token_stream::IntoIter) -> bool {
match tt {
TokenTree::Group(g) => {
let eval = Eval::new_tagged("default", &g);
let result = eval.eval().as_bool();
tt = next_token(iter);
must_be_comma(&tt);
if !result {
return false;
}
}
TokenTree::Ident(i) => {
let mut v = Vec::<TokenTree>::new();
let tag_name = if i.to_string() == "tag" {
tt = next_token(iter);
must_be_assign(&tt);
tt = next_token(iter);
let tag_name = match tt {
TokenTree::Ident(i) => i.to_string(),
_ => panic!("Expected identifier with tag name"),
};
tt = next_token(iter);
must_be_comma(&tt);
tag_name
} else {
let backup = Ident::new(&i.to_string(), i.span());
v.push(TokenTree::Ident(backup));
"default".to_owned()
};
loop {
tt = next_token(iter);
if is_comma(&tt) {
break;
}
v.push(tt);
}
let mut s = TokenStream::new();
s.extend(v.into_iter());
let group = Group::new(Delimiter::Parenthesis, s);
let eval = Eval::new_tagged(&tag_name, &group);
if !eval.eval().as_bool() {
return false;
}
}
TokenTree::Punct(_) | TokenTree::Literal(_) => {
if is_comma(&tt) {
panic!("Expected tag assignment or expression, not comma")
}
let mut v = Vec::<TokenTree>::new();
v.push(tt);
loop {
tt = next_token(iter);
if is_comma(&tt) {
break;
}
v.push(tt);
}
let mut s = TokenStream::new();
s.extend(v.into_iter());
let group = Group::new(Delimiter::Parenthesis, s);
let eval = Eval::new_tagged("default", &group);
if !eval.eval().as_bool() {
return false;
}
}
}
true
}