proc-macro-workshop:seq-2

题解

// The macro invocation in the previous test case contained an empty loop body
// inside the braces. In reality we want for the macro to accept arbitrary
// tokens inside the braces.
//
// The caller should be free to write whatever they want inside the braces. The
// seq macro won't care whether they write a statement, or a function, or a
// struct, or whatever else. So we will work with the loop body as a TokenStream
// rather than as a syntax tree.
//
// Before moving on, ensure that your implementation knows what has been written
// inside the curly braces as a value of type TokenStream.
//
//
// Resources:
//
//   - Explanation of the purpose of proc-macro2:
//     https://docs.rs/proc-macro2/1.0/proc_macro2/

use seq::seq;

macro_rules! expand_to_nothing {
    ($arg:literal) => {
        // nothing
    };
}

seq!(N in 0..4 {
    expand_to_nothing!(N);
});

fn main() {}

这一关我们主要解析的是整个数据的结构。
因为对于N in 0..4并不是标准的语法,我们要解析并且操作,返回符合的标准语法。

解析

impl syn::parse::Parse for crate::parser::SeqParser {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let variable_ident = input.parse::<syn::Ident>()?;
        let _ = input.parse::<syn::Token!(in)>()?;
        let begin = input.parse::<syn::LitInt>()?.base10_parse()?;
        let _ = input.parse::<syn::Token!(..)>()?;
        let end = input.parse::<syn::LitInt>()?.base10_parse()?;
        let body_buf;
        let _ = syn::braced!(body_buf in input);
        let body = body_buf.parse::<proc_macro2::TokenStream>()?;
        syn::Result::Ok(crate::parser::SeqParser {
            variable_ident,
            begin,
            end,
            body,
        })
    }
}

比较值的一提的有三点

  1. 通过parse方法,我们可以自动解析自己想要的数据类型
  2. 使用syn::Token(?)我们可以匹配指定的token
  3. syn::braced!可以抽取{}中的数据,然后慢慢解析

按照前面所述的每个token,我们逐渐的解析了每一个数据。
当然,因为想要支持syn::parse_macro_input!,结构体解析的时候必须要实现syn:: parse::Parse。所以主干的题解可以改成这样了。

主干

#[proc_macro]
pub fn seq(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let _ = syn::parse_macro_input!(input as crate::parser::SeqParser);
    proc_macro2::TokenStream::new().into
}

目前而言,已经支持parse_macro_input!了。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!