使用 syn
库解析语法树时,常常人工编写 Parse
trait 的实现。
最近发现一个基于 syn
和 quote
两个库,具有良好设计和封装的高级库 parsel
,它具有以下亮点:
- 通过自定义类型和
#[derive(Parse, ToTokens)]
的方式,无需重复编写input.parse()
这种“显而易见”的啰嗦代码 - 无缝使用
syn
和quote
库 - 通过类型描述 repetition 和连续标记,见下表
类型 | 含义 |
---|---|
Many | 连续的、无分隔符(或者说空白分隔的)一列标记 |
Any | 任意多的标记 |
Either | 两种标记中的一种 |
Maybe | 相当于 syn 对 Option 的处理(parsel 不处理 Option ) |
Separated | 不含末尾符号的 Punctuated |
例子:使用 parsel 重写我的 async_closure!
声明宏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#![feature(trivial_bounds)]
use parsel::{
ast::{Brace, Ident, Maybe, Punctuated},
parse_quote,
syn::{
token::{Async, Colon, Comma, Eq, Semi},
Expr, ExprClosure, Type,
},
Parse, ToTokens,
};
fn main() {
let _: AsyncClosure = parse_quote!(async || -> usize { f().await });
let _: AsyncClosure = parse_quote!({}; async || -> usize { f().await });
let _: AsyncClosure = parse_quote!({
v: &'a [u8] = &v,
}; async || -> usize { f(v).await });
}
#[derive(PartialEq, Eq, Debug, Parse, ToTokens)]
struct AsyncClosure {
captures: Maybe<Captures>,
_async: Async,
closure: ExprClosure,
}
#[derive(PartialEq, Eq, Debug, Parse, ToTokens)]
struct Capture {
val: Ident,
_colon: Colon,
ty: Type,
_eq: Eq,
expr: Expr,
_comma: Comma,
}
#[derive(PartialEq, Eq, Debug, Parse, ToTokens)]
struct Captures {
captures: Brace<Punctuated<Capture, Comma>>,
semi: Semi,
}
这比声明宏好在:
- 无捕获时,不再需要写
{};
(声明宏也能做到,但肯定没有结构化的类型清晰) - 利用过程宏,可以做更多复杂的事情