Skip to main content

bind

Macro bind 

Source
bind!() { /* proc-macro */ }
Expand description

即时解析宏:在现有的解析逻辑中快速消费 TokenStream On-the-fly parsing macro: Quickly consume a TokenStream within existing parsing logic

bind! 宏模拟了一个 let 绑定语句。其中的核心部分 (<input> -> <pattern>) 会被展开为一个表达式, 其求值结果为 syn::Result<Output>

这意味着你可以像处理普通 Result 一样处理它,例如在后面直接接 ? 操作符、.unwrap() 或者 .map(...)

§语法

vacro::bind!(let <绑定模式> = (<输入流> -> <Vacro模式>) <后续操作>);
  • 绑定模式: 标准 Rust 模式,用于接收解析成功后的内容(如变量名 res 或元组 (a, b))。
  • 输入流: 实现了 Into<TokenStream> 的变量。
  • Vacro模式: 描述语法的模式。
  • 后续操作: 针对 Result 的操作,如 ?;.unwrap(); 等。

§捕获规则

  • 具名捕获 (#(name: Type)): 宏会生成一个包含这些字段的临时结构体 Output
  • 行内捕获 (#(@: Type)): 宏会返回一个元组(或单个值),按照定义的顺序包含捕获的内容。

§示例

fn parser(input: TokenStream) -> Result<()> {
    // 场景 1: 配合 `?` 使用 (推荐)
    // 表达式 `(input -> ...)` 返回 Result,后面接 `?` 传播错误
    let input1 = input.clone();
    bind!(
        let func = (input1 -> fn #(name: Ident))?;
    );
    println!("Function: {}", func.name);

    // 场景 2: 配合 `unwrap` 使用
    // 如果你确定这里一定能解析成功
    let input2 = input.clone();
    bind!(
        let (arrow, ty) = (input2 -> #(@: Token![->]) #(@: Type)).unwrap();
    );

    // 场景 3: 手动处理 Result
    let input3 = input.clone();
    bind!(
        let result = (input3 -> #(kw: Token![mod]));
    );
    if let Ok(output) = result {
        // ...
    }

    Ok(())
}

The bind! macro mimics a let binding statement. The core expression (<input> -> <pattern>) expands to a block that evaluates to syn::Result<Output>.

This means you can treat it like any other Result expression, appending ?, .unwrap(), or .map(...) directly after it.

§Syntax

vacro::bind!(let <binding> = (<input> -> <pattern>) <operations>);
  • binding: Standard Rust pattern to receive the parsed content (e.g., res or (a, b)).
  • input: A variable implementing Into<TokenStream>.
  • pattern: The Vacro pattern description.
  • operations: Operations on the Result, such as ?;, .unwrap();, etc.

§Capture Rules

  • Named Capture (#(name: Type)): Generates a temporary Output struct containing these fields.
  • Inline Capture (#(@: Type)): Returns a tuple (or single value) containing captured items in order.

§Example

fn parser(input: TokenStream) -> Result<()> {
    // Case 1: Using with `?` (Recommended)
    // The expression `(input -> ...)` returns Result, `?` propagates error
    let input1 = input.clone();
    bind!(
        let func = (input1 -> fn #(name: Ident))?;
    );
    println!("Function: {}", func.name);

    // Case 2: Using with `unwrap`
    // If you are sure parsing will succeed
    let input2 = input.clone();
    bind!(
        let (arrow, ty) = (input2 -> #(@: Token![->]) #(@: Type)).unwrap();
    );

    // Case 3: Manually handling Result
    let input3 = input.clone();
    bind!(
        let result = (input3 -> #(kw: Token![mod]));
    );
    if let Ok(output) = result {
        // ...
    }

    Ok(())
}