Problem: Currently, attribute macros require their input to be valid Rust syntax before macro expansion. This causes false errors in tooling (rustc, rust-analyzer) when the macro expects a custom DSL. For example:
#[proc_macro_attribute]
pub fn dummy_attr(_attr: TokenStream, input: TokenStream) -> TokenStream {
//do something
}
fn main() {
#[dummy_attr]
{key:value} // now this give error
#[dummy_attr]
{key::value} //but this is allowed
}
Tools like rust-analyzer flag {key:value}
as invalid Rust syntax during analysis, disrupting developer workflows even though the macro would accept it. Function-like macros don’t have this limitation because they participate in token-tree expansion.
Proposal: Enable attribute macros to declare a custom grammar for their input body. This would instruct tooling to use:
- Rust syntax by default (backward-compatible behavior)
- A macro-specified grammar when explicitly declared
Suggested Implementation: Add a new attribute to mark macros with custom syntax:
#[proc_macro_attribute]
#[custom_grammar = "grammar_identifier"] // New annotation
pub fn my_macro(_attr: TokenStream, input: TokenStream) -> TokenStream { /* ... */ }
Where grammar_identifier
could resolve to:
- A built-in grammar (e.g.,
json
,toml
,ron
) supported natively by tooling - A user-defined grammar via:
- Syn-powered parser: Share logic between the macro and tooling
- TextMate grammar: Leverage existing editor syntax definitions
- WASM-compiled parser: Portable syntax engine
Workflow Integration:
- Compiler: Ignore custom syntax validation in early passes (treat input as token stream)
- rust-analyzer/LSP:
- Use custom parsers for syntax highlighting/validation
- Provide diagnostics based on macro-specific rules
- Use the macro’s grammar for auto-completion in attribute bodies
Motivation:
- Eliminate erroneous errors in IDEs for valid macro input
- Enable rich tooling support for domain-specific syntax
- Unify compiler/tool behavior without changing macro expansion rules
- Backward-compatible via opt-in syntax declaration
Challenges:
- Standardizing Grammar Definitions: Need consensus on cross-tool grammar format
- Parser Sandboxing: Security implications for user-provided parsers
- Performance: On-demand grammar loading to avoid tooling slowdown
Alternatives Considered:
- Do nothing: Forces macros to accept Rust syntax or tolerate tooling noise
- IDE-only solutions: Fragmented support without compiler awareness
- Full syntax plugins: More complex and conflicts with stable Rust
Open Questions:
- Should grammars be definable inline in proc macros?
- How to handle versioning for user-defined grammars?
- Preferred grammar format priority (Syn, TextMate, WASM, etc.)?
Why this approach?
- Clear problem statement with concrete code example
- Backward compatible via opt-in annotation
- Tooling-focused while preserving current compiler behavior
- Practical deployment path using existing ecosystem (Syn/TextMate)
- Exposes tradeoffs and alternatives transparently
This structure aligns with RFC conventions by separating motivation, design, and open questions. The grammar format flexibility increases adoption potential without mandating a single solution.