Skip to content

[Feature] Polymorphic Capture: Enum/Branching Support (A | B Parsing) #9

@FeVeR-Store

Description

@FeVeR-Store

Context

In procedural macro development, we often encounter situations where "a position can be one of multiple types". For example, a macro argument can be either a string literal or an identifier; or like syn::Item, it can be either fn or struct.

Currently, vacro's define! and capture! can only describe linear sequences. To support this polymorphism, we need to introduce Enum Parsing, allowing users to define a set of possible matching branches. vacro will automatically generate try/fork logic and encapsulate the result in a generated Enum.

Target

  1. Branching Syntax: Introduce new DSL syntax to describe branch selection.
  2. Auto Enum Generation: Automatically generate the corresponding Rust enum definition.
  3. Backtracking Logic: Generate backtracking parsing code based on input.fork(), trying branches sequentially.

Architecture Design

1. Syntax Design

It is recommended to use syntax similar to struct initialization:

// Syntax: #( <CaptureName> : <EnumName> { <Type1>, <Type2> } )

define!(MyMacro: 
    kw::input 
    #(content: MyContent { 
        syn::ItemFn,
        ItemStruct 
    })
);

2. AST Changes (src/ast/capture.rs)

Add an Enum variant to the new Matcher enum:

pub enum Matcher {
    SynType(Type),
    Nested(Vec<Pattern>),
    // New Variant
    Enum {
        enum_name: Ident,
        variants: Vec<Matcher>, // Matcher (SynType)
    },
}

3. Codegen Strategy (src/codegen/)

For Matcher::Enum, the generated parsing code should follow this logic:

// Pseudo-code logic
let _fork = input.fork();

if let Ok(v) = _fork.parse::<syn::ItemFn>() {
    input.advance_to(&_fork); // Confirm consumption
    return MyContent::Func(v);
}

let _fork = input.fork();
if let Ok(v) = _fork.parse::<syn::ItemStruct>() {
    input.advance_to(&_fork);
    return MyContent::Struct(v);
}

return Err(Error::new(span, "Expected Func or Struct"));

Task List

Phase 1: AST & Parser Support

  • Add Enum variant to the Matcher enum in src/ast/capture.rs.
  • Update src/syntax/capture.rs parser:
    • Identify Enum { variant, ... } syntax structure.
    • Parse internal branch definitions.

Phase 2: Code Generation (Definition)

  • Update src/codegen/output.rs (generate_output):
    • When Matcher::Enum is detected, generate a pub enum EnumName { ... } definition instead of a struct field.
    • Ensure the generated Enum can be referenced by the outer struct.

Phase 3: Code Generation (Logic)

  • Update src/codegen/logic/capture.rs (Compiler):
    • Implement compile_enum_matcher function.
    • Generate fork -> parse -> advance attempt chain.
    • Generate final Error aggregation ("Expected one of: ...").

Phase 4: Testing

  • Add unit tests: Test simple A | B type selection.
  • Add UI tests: Test error reporting when all branches fail to match.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions