@@ -84,10 +84,10 @@ pub(crate) fn compile_grammar(grammar: &Grammar) -> TokenStream {
8484 continue ;
8585 }
8686
87- if rule. cache . is_some ( ) && !( rule. params . is_empty ( ) && rule . ty_params . is_none ( ) ) {
87+ if rule. cache . is_some ( ) && !rule. cacheable ( ) {
8888 items. push ( report_error (
89- rule. name . span ( ) ,
90- "rules with generics or parameters cannot use #[cache] or #[cache_left_rec]" . to_string ( ) ,
89+ rule. name . span ( ) ,
90+ "rules with generic types or `rule<_>` types cannot use #[cache] or #[cache_left_rec]" . to_string ( ) ,
9191 ) ) ;
9292 continue ;
9393 }
@@ -158,11 +158,29 @@ fn make_parse_state(grammar: &Grammar) -> TokenStream {
158158 let mut cache_fields_def: Vec < TokenStream > = Vec :: new ( ) ;
159159 let mut cache_fields: Vec < Ident > = Vec :: new ( ) ;
160160 for rule in grammar. iter_rules ( ) {
161- if rule. cache . is_some ( ) && rule. params . is_empty ( ) && rule . ty_params . is_none ( ) {
161+ if rule. cache . is_some ( ) && rule. cacheable ( ) {
162162 let name = format_ident ! ( "{}_cache" , rule. name) ;
163163 let ret_ty = rule. ret_type . clone ( ) . unwrap_or_else ( || quote ! ( ( ) ) ) ;
164+
165+ // This could be written more simply as `(usize, #(, #param_ty)*))`,
166+ // but this generates unnecessary brackets when `rule.params` is
167+ // empty, and new releases of clippy have a bad habit of suddenly
168+ // triggering on code generated by proc-macros when `quote_spanned!`
169+ // is used because it thinks that the generated code was handwritten
170+ let key = if rule. params . is_empty ( ) {
171+ quote_spanned ! ( span=> usize )
172+ } else {
173+ let param_ty = rule. params . iter ( ) . map ( |param| {
174+ let RuleParamTy :: Rust ( ty) = & param. ty else {
175+ unreachable ! ( )
176+ } ;
177+ quote_spanned ! ( span=> <:: peg:: chomp_ref!( #ty) as :: std:: borrow:: ToOwned >:: Owned )
178+ } ) ;
179+ quote_spanned ! ( span=> ( usize , #( #param_ty) , * ) )
180+ } ;
181+
164182 cache_fields_def. push (
165- quote_spanned ! { span => #name: :: std:: collections:: HashMap <usize , :: peg:: RuleResult <#ret_ty>> } ,
183+ quote_spanned ! ( span=> #name: :: std:: collections:: HashMap <#key , :: peg:: RuleResult <#ret_ty>>) ,
166184 ) ;
167185 cache_fields. push ( name) ;
168186 }
@@ -274,28 +292,38 @@ fn compile_rule(context: &Context, rule: &Rule) -> TokenStream {
274292 quote ! ( )
275293 } ;
276294
295+ let param = rule. params . iter ( ) . map ( |param| {
296+ let name = & param. name ;
297+ quote_spanned ! ( span=> #name. to_owned( ) )
298+ } ) ;
299+ let key = if rule. params . is_empty ( ) {
300+ quote_spanned ! ( span=> __pos)
301+ } else {
302+ quote_spanned ! ( span=> ( __pos, #( #param) , * ) )
303+ } ;
304+
277305 match cache_type {
278306 Cache :: Simple => quote_spanned ! { span =>
279- if let Some ( entry) = __state. #cache_field. get( & __pos ) {
307+ if let Some ( entry) = __state. #cache_field. get( & #key ) {
280308 #cache_trace
281309 return entry. clone( ) ;
282310 }
283311
284312 let __rule_result = #wrapped_body;
285- __state. #cache_field. insert( __pos , __rule_result. clone( ) ) ;
313+ __state. #cache_field. insert( #key , __rule_result. clone( ) ) ;
286314 __rule_result
287315 } ,
288316 Cache :: Recursive =>
289317 // `#[cache_left_rec] support for recursive rules using the technique described here:
290318 // <https://medium.com/@gvanrossum_83706/left-recursive-peg-grammars-65dab3c580e1>
291319 {
292320 quote_spanned ! { span =>
293- if let Some ( entry) = __state. #cache_field. get( & __pos ) {
321+ if let Some ( entry) = __state. #cache_field. get( & #key ) {
294322 #cache_trace
295323 return entry. clone( ) ;
296324 }
297325
298- __state. #cache_field. insert( __pos , :: peg:: RuleResult :: Failed ) ;
326+ __state. #cache_field. insert( #key , :: peg:: RuleResult :: Failed ) ;
299327 let mut __last_result = :: peg:: RuleResult :: Failed ;
300328 loop {
301329 let __current_result = { #wrapped_body } ;
@@ -305,7 +333,7 @@ fn compile_rule(context: &Context, rule: &Rule) -> TokenStream {
305333 match __last_result {
306334 :: peg:: RuleResult :: Matched ( __last_endpos, _) if __current_endpos <= __last_endpos => break ,
307335 _ => {
308- __state. #cache_field. insert( __pos , __current_result. clone( ) ) ;
336+ __state. #cache_field. insert( #key , __current_result. clone( ) ) ;
309337 __last_result = __current_result;
310338 } ,
311339 }
0 commit comments