af_path 0.2.3

path查询语言库
Documentation
use proc_macro::TokenTree;
use proc_macro::{TokenStream, Punct};

/// 由于rust不支持多操作符单词结构,对多操作符单词结构进行了包装
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
        }
    }

    // 看是否给定group
    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!("必须是标识符")
        }
    }

    // 把单词转换成rust常数
    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!("必须是常数")
        }

    }

    // 把group转换成Tokens
    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")
        }
    }

    // 把单词的string部分转换出来
    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))
        }
    }
}

// 从rust提供的单词流结构读取单词,转换成包装后的单词。rust不支持多操作符,该转换程序对此进行了处理。
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!("不可能不是标识符")
    }
}