使用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
相关产品推荐
相关产品推荐

