// One of the big things callers will want to do with the sequential indices N
// is use them as part of an identifier, like f0 f1 f2 etc.
//
// Implement some logic to paste together any Ident followed by `~` followed by
// our loop variable into a single concatenated identifier.
//
// The invocation below will expand to:
//
// fn f1() -> u64 { 1 * 2 }
// fn f2() -> u64 { 2 * 2 }
// fn f3() -> u64 { 3 * 2 }
//
// Optionally, also support more flexible arrangements like `f~N~_suffix` ->
// f0_suffix f1_suffix etc, though the test suite only requires `prefix~N` so
// you will need to add your own tests for this feature.
//
//
// Resources:
//
// - Example of creating a new Ident from a string:
// https://docs.rs/syn/1.0/syn/struct.Ident.html
use seq::seq;
seq!(N in 1..4 {
fn f~N () -> u64 {
N * 2
}
});
// This f0 is written separately to detect whether your macro correctly starts
// with the first iteration at N=1 as specified in the invocation. If the macro
// incorrectly started at N=0 like in the previous tests cases, the first
// generated function would conflict with this one and the program would not
// compile.
fn f0() -> u64 {
100
}
fn main() {
let sum = f0() + f1() + f2() + f3();
assert_eq!(sum, 100 + 2 + 4 + 6);
}
這裡要解析的是?~N
的形式,我們需要預讀一些token
。
然後將數值帶入,把?~N
轉換為?n
的形式。
// solution4.rs
impl crate::parser::SeqParser {
pub(crate) fn process_prefix(
&self,
idx: &mut usize,
n: usize,
prefix: &syn::Ident,
buf: &Vec<proc_macro2::TokenTree>,
) -> std::option::Option<proc_macro2::TokenStream> {
// 還有解析的空間
if *idx + 2 < buf.len() {
if let proc_macro2::TokenTree::Punct(p) = &buf[*idx + 1] {
// 核對識別符號
if p.as_char() == '~' {
if let proc_macro2::TokenTree::Ident(ident) = &buf[*idx + 2] {
// 核對迴圈變數,並且需要緊密聯絡
if ident == &self.variable_ident
&& prefix.span().end() == p.span().start()
&& p.span().end() == ident.span().start()
{
// 新生成識別符號進行替換
let combine_ident_litral = format!("{}{}", prefix.to_string(), n);
let combine_ident =
syn::Ident::new(&combine_ident_litral, prefix.span());
*idx += 3;
return std::option::Option::Some(quote::quote! {
#combine_ident
});
}
}
}
}
}
std::option::Option::None
}
}
不過,這裡還算是原有邏輯的一個補充,因此,需要在seq-3中進行新增,也就是註釋部分。
整體邏輯保持不變
#[proc_macro]
pub fn seq(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let parser = syn::parse_macro_input!(input as crate::parser::SeqParser);
return parser.expend_repeat().into();
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結