proc-macro-workshop:seq-7

godme發表於2022-07-05
// The previous examples all used an exclusive range, MIN..MAX. Now make it work
// for an inclusive range MIN..=MAX that includes the upper range bound!

use seq::seq;

seq!(N in 16..=20 {
    enum E {
        #(
            Variant~N,
        )*
    }
});

fn main() {
    let e = E::Variant16;

    let desc = match e {
        E::Variant16 => "min",
        E::Variant17 | E::Variant18 | E::Variant19 => "in between",
        E::Variant20 => "max",
    };

    assert_eq!(desc, "min");
}

這一關主要是增加了a..=b中的相等,也就是對end的調整。
解析的時候我們需要預讀一下。

pub(crate) fn parse_range(input: &syn::parse::ParseStream) -> syn::Result<(usize, usize)> {
    let begin = input.parse::<syn::LitInt>()?.base10_parse()?;
    let _ = input.parse::<syn::Token!(..)>()?;
    let mut incude_grater = false;
    if input.peek(syn::Token!(=)) {
        input.parse::<syn::Token!(=)>()?;
        incude_grater = true;
    }
    let mut end = input.parse::<syn::LitInt>()?.base10_parse()?;
    if incude_grater {
        end += 1;
    }
    syn::Result::Ok((begin, end))
}

其中使用peek方法,我們可以預讀一下而不消耗token,十分方便。
這裡parse方法對應的調整即可

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, end) = crate::solution7::parse_range(&input)?;
        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,
        })
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結