@@ -113,3 +113,43 @@ pub fn rule(input: TokenStream) -> TokenStream {
113113 Err ( err) => err. to_compile_error ( ) . into ( ) ,
114114 }
115115}
116+
117+ /// Bundle a list of YEAST rewrite rules with input/output node-types
118+ /// schema paths. Returns a `Vec<Rule>`; substitutable for
119+ /// `vec![rule!(...), ...]`.
120+ ///
121+ /// Each comma-separated item in the bracketed list may be:
122+ ///
123+ /// 1. A **bare rule body** `(query) => (template)` — the `rule!(...)`
124+ /// wrapper is implicit.
125+ /// 2. An explicit `rule!(...)` invocation, possibly chained as
126+ /// `rule!(...).repeated()` or path-prefixed as `yeast::rule!(...)`.
127+ /// 3. Any other expression returning a `Rule` (helper-function calls,
128+ /// conditionals).
129+ ///
130+ /// ```ignore
131+ /// let translation_rules: Vec<yeast::Rule> = yeast::rules! {
132+ /// input: "tree-sitter-swift/node-types.yml",
133+ /// output: "ast_types.yml",
134+ /// [
135+ /// (source_file (_)* @cs) => (top_level body: {..cs}),
136+ /// (simple_identifier) @id => (name_expr identifier: (identifier #{id})),
137+ /// rule!((integer_literal) @lit => (int_literal #{lit})).repeated(),
138+ /// helper_fn(),
139+ /// ]
140+ /// };
141+ /// ```
142+ ///
143+ /// Paths are resolved relative to the consuming crate's `CARGO_MANIFEST_DIR`
144+ /// (the same convention `include_str!` uses for relative paths). The
145+ /// resolved paths are also emitted as `include_str!` references so the
146+ /// consuming crate gets invalidated when a schema YAML changes, prepping
147+ /// the ground for compile-time type-checking against those schemas.
148+ #[ proc_macro]
149+ pub fn rules ( input : TokenStream ) -> TokenStream {
150+ let input2: TokenStream2 = input. into ( ) ;
151+ match parse:: parse_rules_top ( input2) {
152+ Ok ( output) => output. into ( ) ,
153+ Err ( err) => err. to_compile_error ( ) . into ( ) ,
154+ }
155+ }
0 commit comments