proc-macro-workshop:seq-2

godme發表於2022-07-05
// 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 協議》,轉載必須註明作者和本文連結