You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用syn解析Rust过程宏时出现Unexpected token错误的原因

Rust过程宏解析矛盾错误的原因与解决

问题场景

我在学习proc-macro-workshop的seq模块第2个测试时,编写了Seq结构体并实现Parse trait解析宏输入。调试输出显示Parse方法已成功解析出预期内容,但调用syn::parse时却返回错误:unexpected token, expected '}'。

解析代码如下:

use proc_macro::TokenStream as TokenStream1;
use proc_macro2::*;
use syn::*;
use parse::{Parse,ParseStream};

#[derive(Debug)]
struct Seq {
  ident: Ident,
  in_token: Token![in],
  start: LitInt,
  dots_token: Token![..],
  end: LitInt,
  brace_token: token::Brace,
  body: TokenStream,
}

impl Parse for Seq {
  fn parse(input: ParseStream<'_>) -> Result<Self> {
    let content;
    let result = Seq {
      ident: input.parse()?,
      in_token: input.parse()?,
      start: input.parse()?,
      dots_token: input.parse()?,
      end: input.parse()?,
      brace_token: braced!(content in input),
      body: content.cursor().token_stream(),
    };
    Ok(dbg!(result))
  }
}

#[proc_macro]
pub fn seq(input: TokenStream1) -> TokenStream1 {
  let seq: Result<Seq> = syn::parse(input);
  dbg!(seq);

  TokenStream1::default()
}

测试代码:

use seq::seq;

macro_rules! expand_to_nothing {
    ($arg:literal) => {
        // nothing                                                               
    };
}

seq!(N in 0..4 {
    expand_to_nothing!(N);
});

fn main() {}

问题原因

核心矛盾出在**syn::parse要求必须完全消耗输入的所有Token流**,而当前实现未满足这个要求:

  • content.cursor().token_stream()只是获取了花括号内Token流的快照,并没有从content这个ParseStream中消耗这些Token。
  • 当Parse方法返回后,syn::parse会检查输入流是否被完全处理,发现还有剩余Token(花括号内的内容),因此抛出unexpected token错误。
  • 调试时dbg!(result)能显示内容,是因为结构体已经成功构造,但输入流未被完全消耗,两者并不冲突。

解决方法

将获取body的方式改为content.parse::<TokenStream>()?,这会消耗掉花括号内的所有Token,满足syn::parse的完全消耗要求:

修改后的Parse实现:

impl Parse for Seq {
  fn parse(input: ParseStream<'_>) -> Result<Self> {
    let content;
    let result = Seq {
      ident: input.parse()?,
      in_token: input.parse()?,
      start: input.parse()?,
      dots_token: input.parse()?,
      end: input.parse()?,
      brace_token: braced!(content in input),
      body: content.parse()?, // 核心修改处
    };
    Ok(result)
  }
}

修改后,syn::parse就能成功解析输入,不再返回剩余Token的错误。

内容的提问来源于stack exchange,提问作者Jim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:15:59