use proc_macro::TokenTree;
use proc_macro::{TokenStream, Punct};
pub enum Token {
TokenTree(TokenTree),
Oper(String),
}
impl Token {
pub fn is_oper(&self, opers: &[&str]) -> bool {
if let Token::Oper(oper) = self {
opers.contains(&oper.as_str())
} else {
false
}
}
pub fn is_lit(&self) -> bool {
if let Token::TokenTree(token) = self {
if let TokenTree::Literal(_) = token {
true
} else {
false
}
} else {
false
}
}
pub fn is_ident(&self) -> bool {
if let Token::TokenTree(token) = self {
if let TokenTree::Ident(_) = token {
true
} else {
false
}
} else {
false
}
}
pub fn is_spec_ident(&self, idents: &[&str]) -> bool {
if let Token::TokenTree(token) = self {
if let TokenTree::Ident(ident) = token {
idents.contains(&ident.to_string().as_str())
} else {
false
}
} else {
false
}
}
pub fn starts_with(&self, prev: &str) -> bool {
if let Token::TokenTree(token) = self {
if let TokenTree::Ident(ident) = token {
ident.to_string().starts_with(prev)
} else {
false
}
} else {
false
}
}
pub fn is_group(&self, delimiter: proc_macro::Delimiter) -> bool {
if let Token::TokenTree(token) = self {
if let TokenTree::Group(ref group) = token {
group.delimiter() == delimiter
} else {
false
}
} else {
false
}
}
pub fn to_ident(&self) -> syn::Ident {
if let Token::TokenTree(token) = self {
if let TokenTree::Ident(ident) = token {
let name = ident.to_string();
let ident: syn::Ident = syn::parse_str(&name).expect(&format!("标识符要合法, {}", &name));
ident
} else {
panic!("必须是标识符")
}
} else {
panic!("必须是标识符")
}
}
pub fn to_lit(&self) -> syn::Lit {
if let Token::TokenTree(token) = self {
if let TokenTree::Literal(lit) = token {
let lit: syn::Lit = syn::parse_str(&lit.to_string()).expect("常数解析错误");
lit
} else {
panic!("必须是常数")
}
} else {
panic!("必须是常数")
}
}
pub fn to_tokens(&self) -> Tokens {
if let Token::TokenTree(token) = self {
if let TokenTree::Group(ref group) = token {
Tokens::new(group.stream())
} else {
panic!("只有group可以转tokens")
}
} else {
panic!("只有group可以转tokens")
}
}
pub fn to_string(&self) -> String {
match self {
Token::TokenTree(token) => {
match token {
TokenTree::Ident(ident) => ident.to_string(),
_ => panic!("单词不能转字符串")
}
},
Token::Oper(str) => str.to_string()
}
}
}
pub struct Tokens {
pub source: String,
pub iter: Box<dyn Iterator<Item = TokenTree>>,
pub tokens: Vec<Token>,
}
impl Tokens {
pub fn new(stream: TokenStream) -> Self {
let str = stream.to_string();
let iter: Box<dyn Iterator<Item = TokenTree>> = Box::new(stream.into_iter());
Tokens{iter:iter, tokens:Vec::new(), source: str}
}
pub fn to_string(&self) -> String {
self.source.to_string()
}
pub fn back_token(&mut self, token_op: Option<Token>) {
match token_op {
Some(token) => self.tokens.push(token),
None => {},
}
}
pub fn back_tokens(&mut self, tokens: Vec<Token>) {
for v in tokens.into_iter() {
self.tokens.insert(0, v);
}
}
}
impl Iterator for Tokens {
type Item = Token;
fn next(&mut self) -> Option<Self::Item> {
if self.tokens.is_empty() {
get_token(self)
} else {
Some(self.tokens.remove(0))
}
}
}
fn get_token(tokens: &mut Tokens) -> Option<Token> {
let token_op = tokens.iter.next();
match token_op {
None => None,
Some(token) => {
match token {
TokenTree::Punct(punct) => Some(Token::Oper(get_puncts(tokens, &punct))),
_ => Some(Token::TokenTree(token))
}
}
}
}
fn get_puncts(tokens: &mut Tokens, punct: &Punct) -> String {
let mut result = String::new();
result.push(punct.as_char());
if let proc_macro::Spacing::Joint = punct.spacing() {
let ch = get_punct(tokens).as_char();
result.push(ch);
}
result
}
fn get_punct(tokens: &mut Tokens) -> Punct {
let token = tokens.iter.next().expect("后面肯定有值");
match token {
TokenTree::Punct(punct) => punct,
_ => panic!("不可能不是标识符")
}
}