proc-macro-workshop:sorted-2

godme發表於2022-07-06
// The #[sorted] macro is only defined to work on enum types, so this is a test
// to ensure that when it's attached to a struct (or anything else) it produces
// some reasonable error. Your macro will need to look into the syn::Item that
// it parsed to ensure that it represents an enum, returning an error for any
// other type of Item such as a struct.
//
// This is an exercise in exploring how to return errors from procedural macros.
// The goal is to produce an understandable error message which is tailored to
// this specific macro (saying that #[sorted] cannot be applied to things other
// than enum). For this you'll want to look at the syn::Error type, how to
// construct it, and how to return it.
//
// Notice that the return value of an attribute macro is simply a TokenStream,
// not a Result with an error. The syn::Error type provides a method to render
// your error as a TokenStream containing an invocation of the compile_error
// macro.
//
// A final tweak you may want to make is to have the `sorted` function delegate
// to a private helper function which works with Result, so most of the macro
// can be written with Result-returning functions while the top-level function
// handles the conversion down to TokenStream.
//
//
// Resources
//
//   - The syn::Error type:
//     https://docs.rs/syn/1.0/syn/struct.Error.html

use sorted::sorted;

#[sorted]
pub struct Error {
    kind: ErrorKind,
    message: String,
}

enum ErrorKind {
    Io,
    Syntax,
    Eof,
}

fn main() {}

這道題主要是報錯

error: expected enum or match expression
  --> tests/02-not-enum.rs:31:1
   |
31 | #[sorted]
   | ^^^^^^^^^
   |
   = note: this error originates in the attribute macro `sorted` (in Nightly builds, run with -Z macro-backtrace for more info)

標識的是隻能夠標記在enum上。

pub(crate) fn solution(item: &syn::Item) -> syn::Result<proc_macro2::TokenStream> {
    match item {
        syn::Item::Enum(node) => crate::solution3::solution(node),
        _ => syn::Result::Err(syn::Error::new(
            proc_macro2::Span::call_site(),
            "expected enum or match expression",
        )),
    }
}

模式匹配即可,順便引出第三個坑。

proc_macro2:: Span::call_site()真香

#[proc_macro_attribute]
pub fn sorted(
    _args: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let item = syn::parse_macro_input!(input as syn::Item);
    match solution1::solution(&item) {
        syn::Result::Ok(stream) => stream,
        syn::Result::Err(e) => {
            let mut res = e.into_compile_error();
            res.extend(crate::common::to_token_stream(item));
            res
        }
    }
    .into()
}

整體結構不變。

本作品採用《CC 協議》,轉載必須註明作者和本文連結