如何在过程宏中提供有用的编译器错误?

Posted

技术标签:

【中文标题】如何在过程宏中提供有用的编译器错误?【英文标题】:How do I provide helpful compiler errors in a procedural macro? 【发布时间】:2018-08-06 21:24:12 【问题描述】:

我正在使用proc_macrosyn 设计一个自定义html 语法解析器。一个样本:

#[derive(Debug)]
struct BlockElement 
    stag: Ident,
    child: Vec<Element>,
    ctag: Ident


impl Synom for BlockElement 
     named!(parse -> Self, do_parse!(
         punct!(<) >>
         stag: syn!(Ident) >>
         punct!(>) >>
         child: syn!(ElementList) >>
         punct!(<) >>
         punct!(/) >>
         ctag: syn!(Ident) >>
         punct!(>) >>
         (BlockElement  stag, child: child.inner, ctag )
     ));
 

虽然我知道如何在解析后使用Span 给出错误,但我无法弄清楚如何在解析期间执行此操作。它只是与failed to parse anything 出错。如何查明解析失败的位置并给出适当的错误?

【问题讨论】:

我不确定,您最关心的是什么,trace_macros! 和 log_syntax! 对您有帮助吗? 我主要担心这个宏的用户必须自己寻找自定义语法中的任何错误。我希望解析器显示错误发生的位置。 【参考方案1】:

通过升级您的宏以使用Syn 0.15 或更高版本,您无需付出额外的努力即可获得有用的解析错误消息。

extern crate proc_macro;
use self::proc_macro::TokenStream;

use syn::parse::Parse, ParseStream, Result;
use syn::parse_macro_input, Ident, Token;

// FIXME
type Element = Ident;

struct ElementList 
    inner: Vec<Element>,


impl Parse for ElementList 
    fn parse(input: ParseStream) -> Result<Self> 
        let mut list = Vec::new();
        while let Some(element) = input.parse()? 
            list.push(element);
        
        Ok(ElementList  inner: list )
    


struct BlockElement 
    stag: Ident,
    child: Vec<Element>,
    ctag: Ident


impl Parse for BlockElement 
    fn parse(input: ParseStream) -> Result<Self> 
        input.parse::<Token![<]>()?;
        let stag: Ident = input.parse()?;
        input.parse::<Token![>]>()?;
        let child: ElementList = input.parse()?;
        input.parse::<Token![<]>()?;
        input.parse::<Token![/]>()?;
        let ctag: Ident = input.parse()?;
        input.parse::<Token![>]>()?;
        Ok(BlockElement  stag, child: child.inner, ctag )
    


#[proc_macro]
pub fn html_syntax(input: TokenStream) -> TokenStream 
    let _input = parse_macro_input!(input as BlockElement);

    // TODO
    TokenStream::new()

以下是输入解析错误的示例。此类错误将指示输入无法解析的位置以及宏在该位置预期的标记。

fn main() 
    html_syntax!(<em>syn quote proc_macro2<em>);

error: expected `/`
 --> src/main.rs
  |
  |     html_syntax!(<em>syn quote proc_macro2<em>);
  |                                            ^^

【讨论】:

以上是关于如何在过程宏中提供有用的编译器错误?的主要内容,如果未能解决你的问题,请参考以下文章

如何从预处理器宏中识别平台/编译器?

在过程宏中,如何检查字符串是不是是有效的变量名而不是关键字?

如何在 C++ 预处理器宏中处理数组元素?

如何在Rust宏中使用ty

从日期宏中仅提取年份

为什么在定义宏中使用括号会产生错误?