Expand description
§Vacro Parser
Vacro 的声明式解析内核
§简介
Vacro Parser 是 Vacro 框架的核心声明式解析引擎。它提供了一种类似 macro_rules! 的 DSL,用于简化 Rust 过程宏中基于 syn 的解析逻辑。
它允许你声明式地定义 AST 结构和解析逻辑,消除了繁琐的 input.parse()? 调用。
§核心功能
§1. define!:定义解析结构体
使用 define! 定义一个结构体,它会自动实现 syn::parse::Parse。
// 定义一个名为 MyFn 的结构体,它会自动实现 Parse trait
define!(MyFn:
fn
#(?: <#(generic*[,]: GenericParam)>)
#(name: Ident)
( #(args*[,]: FnArg) )
#(?: -> #(ret: Type))
);
fn parse_my_fn(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
// 使用方式
let my_fn: MyFn = parse_quote!(input);
println!("Function name: {}", my_fn.name);
proc_macro2::TokenStream::new()
}§2. bind!:即时流解析
在现有的命令式逻辑中,使用 bind! 快速消费一段 TokenStream。
// 即时解析函数签名模式
bind!(
let captured = (input ->
fn #(name: Ident) #(?: -> #(ret: Type))
)?;
);
// 直接访问捕获的字段
println!("Name: {}", captured.name);
if let Some(ret_type) = captured.ret {
// ...
}§语法参考
| 语法 | 描述 | 解析结果类型 | 示例 |
|---|---|---|---|
literal | 匹配并消费确切的 Token | ! | fn, ->, struct |
#(x: T) | 具名捕获: 捕获类型 T 到字段 x | T | #(name: Ident) |
#(x?: T) | 具名可选: 尝试解析,失败则跳过 | Option<T> | #(ret?: Type) |
#(x*[sep]: T) | 具名迭代: 按分隔符解析 | Punctuated<T, sep> | #(args*[,]: FnArg) |
#(T) | 匿名捕获: 验证 T 存在但不捕获 | ! | #(Ident) |
#(?: T) | 匿名可选: 仅作验证 | ! | #(?: Ident) |
#(*[sep]: T) | 匿名迭代: 仅作验证 | ! | #(*[,]: Ident) |
§多态捕获 (Enum Parsing)
Vacro 支持解析“多态”结构,即输入流中的某个位置可能是多种类型之一。
define!(MyPoly:
#(data: MyEnum {
Ident, // 1. 简写:匹配 Ident,生成 MyEnum::Ident(Ident)
syn::Type, // 2. 简写:匹配 Type,生成 MyEnum::Type(syn::Type)
Integer: syn::LitInt, // 3. 别名:匹配 LitInt,生成 MyEnum::Integer(LitInt)
Function: fn #(name: Ident), // 4. 模式:生成 MyEnum::Function { name: Ident }
Tuple: (#(@: Ident), #(@: Expr)), // 5. 模式:生成 MyEnum::Tuple(Ident, Expr)
})
);§更友好的提示 (v0.1.6)
你可以使用vacro-report的help!宏为内容提供更友好的提示,若你使用了vacro,只需要开启reportfeature即可。
vacro_parser = { version: "0.1.7" }
vacro_report = { version: "0.1.3", features: ["parser"] }
# vacro = { version: "0.2.2", features: ["parser", "report"] }use vacro_parser::define;
use vacro_report::help;
help!(Bool:
LitBool {
error: "此处需要一个bool字面量,接收到的是:{input}",
help: "尝试`true`或`false`",
example: (true | false) // example 字段是要展示的示例字段,在生成错误信息与使用示例时使用;它接受一段TokenStream,并且将直接展示你传入的内容
}
);
define!(MyRoles: {
#(roles*[,]: #(pair: #(name: syn::Ident): #(enable: Bool)))
});
此示例不能通过编译,其中使用的关联捕获语法#(pair: #(name: Ident): #(enable: BoolLit))将在后续实现,参见关联捕获
§Vacro Parser
The Declarative Parsing Kernel for Vacro
§Introduction
Vacro Parser is the core declarative parsing engine of the Vacro framework. It provides a macro_rules!-like DSL to simplify the writing of syn-based parsers for Rust Procedural Macros.
It allows you to define AST structures and parsing logic declaratively, eliminating the boilerplate of imperative input.parse()? calls.
§Core Features
§1. define!: Define Parsing Structs
Use define! to define a struct that automatically implements syn::parse::Parse.
// Define a struct named MyFn, it automatically implements the Parse trait
define!(MyFn:
fn
#(?: <#(generic*[,]: GenericParam)>)
#(name: Ident)
( #(args*[,]: FnArg) )
#(?: -> #(ret: Type))
);
fn parse_my_fn(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
// Usage
let my_fn: MyFn = parse_quote!(input);
println!("Function name: {}", my_fn.name);
proc_macro2::TokenStream::new()
}§2. bind!: On-the-fly Parsing
Use bind! to consume a portion of a TokenStream within existing imperative logic.
// Parse a function signature pattern on the fly
bind!(
let captured = (input ->
fn #(name: Ident) #(?: -> #(ret: Type))
)?;
);
// Access captured fields directly
println!("Name: {}", captured.name);
if let Some(ret_type) = captured.ret {
// ...
}§Syntax Reference
| Syntax | Description | Result Type | Example |
|---|---|---|---|
literal | Matches and consumes exact tokens | ! | fn, ->, struct |
#(x: T) | Named Capture: Captures type T into field x | T | #(name: Ident) |
#(x?: T) | Named Optional: Attempts to parse; skips if failed | Option<T> | #(ret?: Type) |
#(x*[sep]: T) | Named Iter: Parses by separator | Punctuated<T, sep> | #(args*[,]: FnArg) |
#(T) | Anonymous Match: Validates T exists but doesn’t capture | ! | #(Ident) |
#(?: T) | Anonymous Optional: Validation only | ! | #(?: Ident) |
#(*[sep]: T) | Anonymous Iter: Validation only | ! | #(*[,]: Ident) |
§Polymorphic Capture (Enum Parsing)
Vacro supports parsing “polymorphic” structures, where a position in the input stream can be one of multiple types.
define!(MyPoly:
#(data: MyEnum {
Ident, // 1. Shorthand: Match Ident, produces MyEnum::Ident(Ident)
syn::Type, // 2. Shorthand: Match Type, produces MyEnum::Type(syn::Type)
Integer: syn::LitInt, // 3. Alias: Match LitInt, produces MyEnum::Integer(LitInt)
Function: fn #(name: Ident), // 4. Pattern: Produces MyEnum::Function { name: Ident }
Tuple: (#(@: Ident), #(@: Expr)), // 5. Pattern: Produces MyEnum::Tuple(Ident, Expr)
})
);§More user-friendly prompts (v0.1.6)
You can use the help! macro of vacro-report to provide more helpful suggestions for the content. If you are using vacro, you only need to enable the report feature.
vacro_parser = { version: "0.1.7" }
vacro_report = { version: "0.1.3", features: ["parser"] }
# vacro = { version: "0.2.2", features: ["parser", "report"] }use vacro_parser::define;
use vacro_report::help;
help!(Bool:
LitBool {
error: "A boolean literal is required here; the received value is: {input}",
help: "Try `true` or `false`",
example: (true | false) // The example field is the sample field to be displayed, used when generating error messages and usage examples; it accepts a TokenStream and will directly display the content you pass in.
}
);
define!(MyRoles: {
#(roles*[,]: #(pair: #(name: syn::Ident): #(enable: Bool)))
});
This example fails to compile. The associated capture syntax #(pair: #(name: Ident): #(enable: BoolLit)) used here will be implemented later; see Associated Captures