From 966252a598cf3aab9dad2edded1dd6485be1eb54 Mon Sep 17 00:00:00 2001 From: matt rice Date: Wed, 26 Aug 2026 12:49:29 -0700 Subject: [PATCH 01/10] Add grmtools_section to ast --- cfgrammar/src/lib/header.rs | 83 ++++++++++++++++++++++++++++++-- cfgrammar/src/lib/yacc/ast.rs | 20 +++++++- cfgrammar/src/lib/yacc/parser.rs | 10 +++- 3 files changed, 106 insertions(+), 7 deletions(-) diff --git a/cfgrammar/src/lib/header.rs b/cfgrammar/src/lib/header.rs index fcd8963ea..57c07ecc3 100644 --- a/cfgrammar/src/lib/header.rs +++ b/cfgrammar/src/lib/header.rs @@ -48,7 +48,7 @@ impl Spanned for HeaderError { // This is essentially a tuple that needs a newtype so we can implement `From` for it. // Thus we aren't worried about it being `pub`. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] #[doc(hidden)] pub struct HeaderValue(pub T, pub Value); @@ -71,6 +71,15 @@ pub enum HeaderErrorKind { ConversionError(&'static str, &'static str), } +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum GrmtoolsSectionValue { + String(String, Span), + Num(u64, Span), + Bool(bool, Span), + Array(Vec, Span), + RustLike(String, Span), +} + impl fmt::Display for HeaderErrorKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { @@ -116,14 +125,14 @@ impl HeaderError { /// member: ("Bar", ...) /// } /// ``` -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] #[doc(hidden)] pub struct Namespaced { pub namespace: Option<(String, T)>, pub member: (String, T), } -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] #[doc(hidden)] pub enum Setting { /// A value like `YaccKind::Grmtools` @@ -152,7 +161,7 @@ pub struct GrmtoolsSectionParser<'input> { /// /// To be useful across diverse crates this types fields are limited to types derived from `core::` types. /// like booleans, numeric types, and string values. -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] #[doc(hidden)] pub enum Value { Flag(bool, T), @@ -236,6 +245,72 @@ impl Namespaced { } } +impl From> for GrmtoolsSectionValue { + fn from(value: Value) -> GrmtoolsSectionValue { + match value { + Value::Flag(value, value_span) => GrmtoolsSectionValue::Bool(value, value_span), + Value::Setting(setting) => match setting { + Setting::Array(v, start_span, end_span) => { + let array_span = Span::new(start_span.start(), end_span.end()); + let mut out = Vec::with_capacity(v.capacity()); + for setting in v { + // To Call this function recursively we need to convert the `Setting` to a `HeaderValue` + out.push(GrmtoolsSectionValue::from(Value::Setting(setting))); + } + GrmtoolsSectionValue::Array(out, array_span) + } + Setting::String(s, val_span) => GrmtoolsSectionValue::String(s.clone(), val_span), + Setting::Num(n, val_span) => GrmtoolsSectionValue::Num(n, val_span), + Setting::Unitary(Namespaced { + namespace, + member: (member, member_span), + }) => { + let mut s = String::new(); + let mut start_pos = member_span.start(); + if let Some((ns, ns_span)) = namespace { + s.push_str(&ns); + s.push_str("::"); + start_pos = ns_span.start(); + } + s.push_str(&member); + GrmtoolsSectionValue::RustLike(s, Span::new(start_pos, member_span.end())) + } + Setting::Constructor { + ctor: + Namespaced { + namespace: ctor_namespace, + member: (ctor_member, ctor_member_span), + }, + arg: + Namespaced { + namespace: arg_namespace, + member: (arg_member, arg_member_span), + }, + } => { + let mut s = String::new(); + let mut ctor_start_pos = ctor_member_span.start(); + if let Some((ns, namespace_span)) = ctor_namespace { + ctor_start_pos = namespace_span.start(); + s.push_str(&ns); + s.push_str("::"); + } + s.push_str(&ctor_member); + s.push('('); + if let Some((arg_ns, _)) = arg_namespace { + s.push_str(&arg_ns); + } + s.push_str(&arg_member); + s.push(')'); + GrmtoolsSectionValue::RustLike( + s, + Span::new(ctor_start_pos, arg_member_span.end()), + ) + } + }, + } + } +} + static RE_LEADING_WS: LazyLock = LazyLock::new(|| Regex::new(r"^[\p{Pattern_White_Space}]*").unwrap()); static RE_NAME: LazyLock = LazyLock::new(|| { diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index fb1ef5cb2..8ee495f48 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -14,7 +14,9 @@ use super::{ use crate::{ Span, - header::{GrmtoolsSectionParser, HeaderError, HeaderErrorKind, HeaderValue}, + header::{ + GrmtoolsSectionParser, GrmtoolsSectionValue, HeaderError, HeaderErrorKind, HeaderValue, + }, yacc::YaccOriginalActionKind, }; @@ -178,6 +180,7 @@ pub struct GrammarAST { // The set of symbol names that, if unused in a // grammar, will not cause a warning or error. pub expect_unused: Vec, + pub grmtools_section: HashMap, } #[derive(Debug, Clone)] @@ -255,6 +258,7 @@ impl GrammarAST { parse_generics: None, programs: None, expect_unused: Vec::new(), + grmtools_section: HashMap::new(), } } @@ -543,6 +547,20 @@ impl GrammarAST { }), ) } + + pub fn grmtools_section_values( + &self, + ) -> impl Iterator { + self.grmtools_section.iter() + } + + pub fn grmtools_section_values_for_crate( + &self, + crate_name: &str, + ) -> impl Iterator { + self.grmtools_section_values() + .filter(move |(key, _)| key.starts_with(&format!("{crate_name}."))) + } } #[cfg(test)] diff --git a/cfgrammar/src/lib/yacc/parser.rs b/cfgrammar/src/lib/yacc/parser.rs index 4ee8eec99..c29d91a20 100644 --- a/cfgrammar/src/lib/yacc/parser.rs +++ b/cfgrammar/src/lib/yacc/parser.rs @@ -16,7 +16,7 @@ use wincode::{SchemaRead, SchemaWrite}; use crate::{ Span, Spanned, - header::{GrmtoolsSectionParser, HeaderErrorKind}, + header::{GrmtoolsSectionParser, GrmtoolsSectionValue, HeaderErrorKind, HeaderValue}, }; pub type YaccGrammarResult = Result>; @@ -337,9 +337,15 @@ impl YaccParser<'_> { pub(crate) fn parse(&mut self) -> YaccGrammarResult { let mut errs = Vec::new(); - let (_, pos) = GrmtoolsSectionParser::new(self.src, false) + let (header, pos) = GrmtoolsSectionParser::new(self.src, false) .parse() .map_err(|mut errs| errs.drain(..).map(|e| e.into()).collect::>())?; + for (key, HeaderValue(key_span, value)) in header.into_iter() { + let value = value.clone(); + self.ast + .grmtools_section + .insert(key.clone(), (*key_span, GrmtoolsSectionValue::from(value))); + } // We pass around an index into the *bytes* of self.src. We guarantee that at all times // this points to the beginning of a UTF-8 character (since multibyte characters exist, not // every byte within the string is also a valid character). From 660969276584362aa539a4775e96548d5710be74 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 03:03:48 -0700 Subject: [PATCH 02/10] Add test cases for `grmtools_section_values_for_crate` --- cfgrammar/src/lib/yacc/ast.rs | 164 ++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index 8ee495f48..83ac20e97 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -1002,4 +1002,168 @@ start -> () : "a" {$;;;; }; }] ); } + + #[test] + fn test_grmtools_section() { + use super::*; + let src = r#" +%grmtools { + yacckind: Grmtools, + lrpar.recoverer: CPCTPlus, + test.flag, + !test.negative, + test.string: "Foo", + test.vec: ["Aaaa", "Bbbb"], + test.num: 1234, +} +%token a +%% +start -> () : "a" { () }; +"#; + let ast_validity = ASTWithValidityInfo::new(YaccKind::Grmtools, src); + let test_flag_span_start = src.find("test.flag").unwrap(); + let test_flag_span = Span::new( + test_flag_span_start, + test_flag_span_start + "test.flag".len(), + ); + let test_neg_span_start = src.find("test.negative").unwrap(); + let test_neg_span = Span::new( + test_neg_span_start, + test_neg_span_start + "test.negative".len(), + ); + let test_string_span_start = src.find("test.string").unwrap(); + let test_string_span = Span::new( + test_string_span_start, + test_string_span_start + "test.string".len(), + ); + let test_string_val_span_start = src.find("Foo").unwrap(); + let test_string_val_span = Span::new( + test_string_val_span_start, + test_string_val_span_start + "Foo".len(), + ); + let test_vec_span_start = src.find("test.vec").unwrap(); + let test_vec_span = Span::new(test_vec_span_start, test_vec_span_start + "test.vec".len()); + let test_vec_a_span_start = src.find("Aaaa").unwrap(); + let test_vec_a_span = + Span::new(test_vec_a_span_start, test_vec_a_span_start + "Aaaa".len()); + let test_vec_b_span_start = src.find("Bbbb").unwrap(); + let test_vec_b_span = + Span::new(test_vec_b_span_start, test_vec_b_span_start + "Bbbb".len()); + let test_vec_val_span_start = src.find("[\"Aaaa\", \"Bbbb\"]").unwrap(); + let test_vec_val_span = Span::new( + test_vec_val_span_start, + test_vec_val_span_start + "[\"Aaaa\", \"Bbbb\"]".len(), + ); + let test_num_span_start = src.find("test.num").unwrap(); + let test_num_span = Span::new(test_num_span_start, test_num_span_start + "test.num".len()); + let test_num_val_span_start = src.find("1234").unwrap(); + let test_num_val_span = Span::new( + test_num_val_span_start, + test_num_val_span_start + "1234".len(), + ); + + let mut test_crate_expected = HashMap::new(); + test_crate_expected.insert( + "test.flag".to_string(), + ( + test_flag_span, + GrmtoolsSectionValue::Bool(true, test_flag_span), + ), + ); + test_crate_expected.insert( + "test.negative".to_string(), + ( + test_neg_span, + GrmtoolsSectionValue::Bool( + false, + Span::new( + test_neg_span_start - 1, + test_neg_span_start + "test.negative".len(), + ), + ), + ), + ); + test_crate_expected.insert( + "test.string".to_string(), + ( + test_string_span, + GrmtoolsSectionValue::String("Foo".to_string(), test_string_val_span), + ), + ); + test_crate_expected.insert( + "test.vec".to_string(), + ( + test_vec_span, + GrmtoolsSectionValue::Array( + vec![ + GrmtoolsSectionValue::String("Aaaa".to_string(), test_vec_a_span), + GrmtoolsSectionValue::String("Bbbb".to_string(), test_vec_b_span), + ], + test_vec_val_span, + ), + ), + ); + test_crate_expected.insert( + "test.num".to_string(), + ( + test_num_span, + GrmtoolsSectionValue::Num(1234, test_num_val_span), + ), + ); + let test_crate_parsed = ast_validity + .ast() + .grmtools_section_values_for_crate("test") + .map(|(key, (key_span, val))| (key.clone(), (*key_span, val.clone()))) + .collect::>(); + assert_eq!(test_crate_parsed, test_crate_expected); + + let mut cfgrammar_crate_expected = HashMap::new(); + let yacckind_span_start = src.find("yacckind").unwrap(); + let yacckind_span = Span::new(yacckind_span_start, yacckind_span_start + "yacckind".len()); + let yacckind_val_span_start = src.find("Grmtools").unwrap(); + let yacckind_val_span = Span::new( + yacckind_val_span_start, + yacckind_val_span_start + "Grmtools".len(), + ); + cfgrammar_crate_expected.insert( + "cfgrammar.yacckind".to_string(), + ( + yacckind_span, + // The actual value we receive has been lower cased + GrmtoolsSectionValue::RustLike("grmtools".to_string(), yacckind_val_span), + ), + ); + let cfgrammar_crate_parsed = ast_validity + .ast() + .grmtools_section_values_for_crate("cfgrammar") + .map(|(key, (key_span, val))| (key.clone(), (*key_span, val.clone()))) + .collect::>(); + assert_eq!(cfgrammar_crate_parsed, cfgrammar_crate_expected); + + let mut lrpar_crate_expected = HashMap::new(); + let recoverer_span_start = src.find("lrpar.recoverer").unwrap(); + let recoverer_span = Span::new( + recoverer_span_start, + recoverer_span_start + "lrpar.recoverer".len(), + ); + let recoverer_val_span_start = src.find("CPCTPlus").unwrap(); + let recoverer_val_span = Span::new( + recoverer_val_span_start, + recoverer_val_span_start + "CPCTPlus".len(), + ); + lrpar_crate_expected.insert( + "lrpar.recoverer".to_string(), + ( + recoverer_span, + // The actual value we receive has been lower cased + GrmtoolsSectionValue::RustLike("cpctplus".to_string(), recoverer_val_span), + ), + ); + let lrpar_crate_parsed = ast_validity + .ast() + .grmtools_section_values_for_crate("lrpar") + .map(|(key, (key_span, val))| (key.clone(), (*key_span, val.clone()))) + .collect::>(); + assert_eq!(lrpar_crate_parsed, lrpar_crate_expected); + } } From 4200d4499bd23d6c97c31d993c78f643c64f14d2 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 03:05:23 -0700 Subject: [PATCH 03/10] Fix out of date comment --- cfgrammar/src/lib/header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cfgrammar/src/lib/header.rs b/cfgrammar/src/lib/header.rs index 57c07ecc3..9acc15040 100644 --- a/cfgrammar/src/lib/header.rs +++ b/cfgrammar/src/lib/header.rs @@ -254,7 +254,7 @@ impl From> for GrmtoolsSectionValue { let array_span = Span::new(start_span.start(), end_span.end()); let mut out = Vec::with_capacity(v.capacity()); for setting in v { - // To Call this function recursively we need to convert the `Setting` to a `HeaderValue` + // To call this function recursively we need to convert the `Setting` to a `Value` out.push(GrmtoolsSectionValue::from(Value::Setting(setting))); } GrmtoolsSectionValue::Array(out, array_span) From d766f4eeec443fc4417288994cf8e76a05e1c448 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 03:26:30 -0700 Subject: [PATCH 04/10] Improve test readability --- cfgrammar/src/lib/yacc/ast.rs | 62 ++++++++++------------------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index 83ac20e97..5b090451a 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -1020,48 +1020,23 @@ start -> () : "a" {$;;;; }; %% start -> () : "a" { () }; "#; - let ast_validity = ASTWithValidityInfo::new(YaccKind::Grmtools, src); - let test_flag_span_start = src.find("test.flag").unwrap(); - let test_flag_span = Span::new( - test_flag_span_start, - test_flag_span_start + "test.flag".len(), - ); - let test_neg_span_start = src.find("test.negative").unwrap(); - let test_neg_span = Span::new( - test_neg_span_start, - test_neg_span_start + "test.negative".len(), - ); - let test_string_span_start = src.find("test.string").unwrap(); - let test_string_span = Span::new( - test_string_span_start, - test_string_span_start + "test.string".len(), - ); - let test_string_val_span_start = src.find("Foo").unwrap(); - let test_string_val_span = Span::new( - test_string_val_span_start, - test_string_val_span_start + "Foo".len(), - ); - let test_vec_span_start = src.find("test.vec").unwrap(); - let test_vec_span = Span::new(test_vec_span_start, test_vec_span_start + "test.vec".len()); - let test_vec_a_span_start = src.find("Aaaa").unwrap(); - let test_vec_a_span = - Span::new(test_vec_a_span_start, test_vec_a_span_start + "Aaaa".len()); - let test_vec_b_span_start = src.find("Bbbb").unwrap(); - let test_vec_b_span = - Span::new(test_vec_b_span_start, test_vec_b_span_start + "Bbbb".len()); - let test_vec_val_span_start = src.find("[\"Aaaa\", \"Bbbb\"]").unwrap(); - let test_vec_val_span = Span::new( - test_vec_val_span_start, - test_vec_val_span_start + "[\"Aaaa\", \"Bbbb\"]".len(), - ); - let test_num_span_start = src.find("test.num").unwrap(); - let test_num_span = Span::new(test_num_span_start, test_num_span_start + "test.num".len()); - let test_num_val_span_start = src.find("1234").unwrap(); - let test_num_val_span = Span::new( - test_num_val_span_start, - test_num_val_span_start + "1234".len(), - ); + let ast_validity = ASTWithValidityInfo::from_str(src).unwrap(); + let find_span = |s: &str| { + let start_pos = src.find(s).unwrap(); + Span::new(start_pos, start_pos + s.len()) + }; + let test_flag_span = find_span("test.flag"); + let test_neg_span = find_span("test.negative"); + let test_neg_val_span = find_span("!test.negative"); + let test_string_span = find_span("test.string"); + let test_string_val_span = find_span("Foo"); + let test_vec_span = find_span("test.vec"); + let test_vec_a_span = find_span("Aaaa"); + let test_vec_b_span = find_span("Bbbb"); + let test_vec_val_span = find_span("[\"Aaaa\", \"Bbbb\"]"); + let test_num_span = find_span("test.num"); + let test_num_val_span = find_span("1234"); let mut test_crate_expected = HashMap::new(); test_crate_expected.insert( "test.flag".to_string(), @@ -1076,10 +1051,7 @@ start -> () : "a" { () }; test_neg_span, GrmtoolsSectionValue::Bool( false, - Span::new( - test_neg_span_start - 1, - test_neg_span_start + "test.negative".len(), - ), + test_neg_val_span, ), ), ); From 8295c6ac35b16edec6ead2f18b4c71dedd365125 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 04:12:58 -0700 Subject: [PATCH 05/10] More tests and test cleanup --- cfgrammar/src/lib/header.rs | 3 +- cfgrammar/src/lib/yacc/ast.rs | 101 +++++++++++++++++++++------------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/cfgrammar/src/lib/header.rs b/cfgrammar/src/lib/header.rs index 9acc15040..e753d86a3 100644 --- a/cfgrammar/src/lib/header.rs +++ b/cfgrammar/src/lib/header.rs @@ -298,12 +298,13 @@ impl From> for GrmtoolsSectionValue { s.push('('); if let Some((arg_ns, _)) = arg_namespace { s.push_str(&arg_ns); + s.push_str("::"); } s.push_str(&arg_member); s.push(')'); GrmtoolsSectionValue::RustLike( s, - Span::new(ctor_start_pos, arg_member_span.end()), + Span::new(ctor_start_pos, arg_member_span.end() + ")".len()), ) } }, diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index 5b090451a..f783b7ee4 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -1004,7 +1004,7 @@ start -> () : "a" {$;;;; }; } #[test] - fn test_grmtools_section() { + fn test_grmtools_section_values() { use super::*; let src = r#" %grmtools { @@ -1021,22 +1021,17 @@ start -> () : "a" {$;;;; }; start -> () : "a" { () }; "#; let ast_validity = ASTWithValidityInfo::from_str(src).unwrap(); - - let find_span = |s: &str| { - let start_pos = src.find(s).unwrap(); - Span::new(start_pos, start_pos + s.len()) - }; - let test_flag_span = find_span("test.flag"); - let test_neg_span = find_span("test.negative"); - let test_neg_val_span = find_span("!test.negative"); - let test_string_span = find_span("test.string"); - let test_string_val_span = find_span("Foo"); - let test_vec_span = find_span("test.vec"); - let test_vec_a_span = find_span("Aaaa"); - let test_vec_b_span = find_span("Bbbb"); - let test_vec_val_span = find_span("[\"Aaaa\", \"Bbbb\"]"); - let test_num_span = find_span("test.num"); - let test_num_val_span = find_span("1234"); + let test_flag_span = src.find_span("test.flag"); + let test_neg_span = src.find_span("test.negative"); + let test_neg_val_span = src.find_span("!test.negative"); + let test_string_span = src.find_span("test.string"); + let test_string_val_span = src.find_span("Foo"); + let test_vec_span = src.find_span("test.vec"); + let test_vec_a_span = src.find_span("Aaaa"); + let test_vec_b_span = src.find_span("Bbbb"); + let test_vec_val_span = src.find_span("[\"Aaaa\", \"Bbbb\"]"); + let test_num_span = src.find_span("test.num"); + let test_num_val_span = src.find_span("1234"); let mut test_crate_expected = HashMap::new(); test_crate_expected.insert( "test.flag".to_string(), @@ -1049,10 +1044,7 @@ start -> () : "a" { () }; "test.negative".to_string(), ( test_neg_span, - GrmtoolsSectionValue::Bool( - false, - test_neg_val_span, - ), + GrmtoolsSectionValue::Bool(false, test_neg_val_span), ), ); test_crate_expected.insert( @@ -1090,13 +1082,8 @@ start -> () : "a" { () }; assert_eq!(test_crate_parsed, test_crate_expected); let mut cfgrammar_crate_expected = HashMap::new(); - let yacckind_span_start = src.find("yacckind").unwrap(); - let yacckind_span = Span::new(yacckind_span_start, yacckind_span_start + "yacckind".len()); - let yacckind_val_span_start = src.find("Grmtools").unwrap(); - let yacckind_val_span = Span::new( - yacckind_val_span_start, - yacckind_val_span_start + "Grmtools".len(), - ); + let yacckind_span = src.find_span("yacckind"); + let yacckind_val_span = src.find_span("Grmtools"); cfgrammar_crate_expected.insert( "cfgrammar.yacckind".to_string(), ( @@ -1113,16 +1100,8 @@ start -> () : "a" { () }; assert_eq!(cfgrammar_crate_parsed, cfgrammar_crate_expected); let mut lrpar_crate_expected = HashMap::new(); - let recoverer_span_start = src.find("lrpar.recoverer").unwrap(); - let recoverer_span = Span::new( - recoverer_span_start, - recoverer_span_start + "lrpar.recoverer".len(), - ); - let recoverer_val_span_start = src.find("CPCTPlus").unwrap(); - let recoverer_val_span = Span::new( - recoverer_val_span_start, - recoverer_val_span_start + "CPCTPlus".len(), - ); + let recoverer_span = src.find_span("lrpar.recoverer"); + let recoverer_val_span = src.find_span("CPCTPlus"); lrpar_crate_expected.insert( "lrpar.recoverer".to_string(), ( @@ -1138,4 +1117,50 @@ start -> () : "a" { () }; .collect::>(); assert_eq!(lrpar_crate_parsed, lrpar_crate_expected); } + + #[test] + fn test_grmtools_section_values2() { + use super::*; + let src = r#" +%grmtools { + yacckind: Original(YaccOriginalActionKind::UserAction), +} +%token a +%actiontype () +%% +start: "a" { () }; +"#; + let ast_validity = ASTWithValidityInfo::from_str(src).unwrap(); + let mut cfgrammar_crate_expected = HashMap::new(); + let yacckind_span = src.find_span("yacckind"); + let yacckind_val_span = src.find_span("Original(YaccOriginalActionKind::UserAction)"); + cfgrammar_crate_expected.insert( + "cfgrammar.yacckind".to_string(), + ( + yacckind_span, + // The actual value we receive has been lower cased + GrmtoolsSectionValue::RustLike( + "original(yaccoriginalactionkind::useraction)".to_string(), + yacckind_val_span, + ), + ), + ); + let cfgrammar_crate_parsed = ast_validity + .ast() + .grmtools_section_values_for_crate("cfgrammar") + .map(|(key, (key_span, val))| (key.clone(), (*key_span, val.clone()))) + .collect::>(); + assert_eq!(cfgrammar_crate_parsed, cfgrammar_crate_expected); + } + + trait FindSpan { + fn find_span(&self, s: &str) -> Span; + } + + impl FindSpan for &'_ str { + fn find_span(&self, s: &str) -> Span { + let start_pos = self.find(s).unwrap(); + Span::new(start_pos, start_pos + s.len()) + } + } } From 4926874afa752e94c5ab9f2e2553e4fb16cb6492 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 04:19:48 -0700 Subject: [PATCH 06/10] Exhaustively check `GrmtoolsSectionValue::RustLike` values --- cfgrammar/src/lib/yacc/ast.rs | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index f783b7ee4..12e674b8f 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -1153,6 +1153,76 @@ start: "a" { () }; assert_eq!(cfgrammar_crate_parsed, cfgrammar_crate_expected); } + #[test] + fn test_grmtools_section_values3() { + use super::*; + let src = r#" +%grmtools { + yacckind: YaccKind::Original(YaccOriginalActionKind::UserAction), +} +%token a +%actiontype () +%% +start: "a" { () }; +"#; + let ast_validity = ASTWithValidityInfo::from_str(src).unwrap(); + let mut cfgrammar_crate_expected = HashMap::new(); + let yacckind_span = src.find_span("yacckind"); + let yacckind_val_span = src.find_span("YaccKind::Original(YaccOriginalActionKind::UserAction)"); + cfgrammar_crate_expected.insert( + "cfgrammar.yacckind".to_string(), + ( + yacckind_span, + // The actual value we receive has been lower cased + GrmtoolsSectionValue::RustLike( + "yacckind::original(yaccoriginalactionkind::useraction)".to_string(), + yacckind_val_span, + ), + ), + ); + let cfgrammar_crate_parsed = ast_validity + .ast() + .grmtools_section_values_for_crate("cfgrammar") + .map(|(key, (key_span, val))| (key.clone(), (*key_span, val.clone()))) + .collect::>(); + assert_eq!(cfgrammar_crate_parsed, cfgrammar_crate_expected); + } + + #[test] + fn test_grmtools_section_values4() { + use super::*; + let src = r#" +%grmtools { + yacckind: YaccKind::Original(UserAction), +} +%token a +%actiontype () +%% +start: "a" { () }; +"#; + let ast_validity = ASTWithValidityInfo::from_str(src).unwrap(); + let mut cfgrammar_crate_expected = HashMap::new(); + let yacckind_span = src.find_span("yacckind"); + let yacckind_val_span = src.find_span("YaccKind::Original(UserAction)"); + cfgrammar_crate_expected.insert( + "cfgrammar.yacckind".to_string(), + ( + yacckind_span, + // The actual value we receive has been lower cased + GrmtoolsSectionValue::RustLike( + "yacckind::original(useraction)".to_string(), + yacckind_val_span, + ), + ), + ); + let cfgrammar_crate_parsed = ast_validity + .ast() + .grmtools_section_values_for_crate("cfgrammar") + .map(|(key, (key_span, val))| (key.clone(), (*key_span, val.clone()))) + .collect::>(); + assert_eq!(cfgrammar_crate_parsed, cfgrammar_crate_expected); + } + trait FindSpan { fn find_span(&self, s: &str) -> Span; } From 7f4847a4c5f8c14b1478ed42adbbd2741343ae57 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 04:35:05 -0700 Subject: [PATCH 07/10] test key case insensitivity --- cfgrammar/src/lib/yacc/ast.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index 12e674b8f..d294645e3 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -1008,10 +1008,10 @@ start -> () : "a" {$;;;; }; use super::*; let src = r#" %grmtools { - yacckind: Grmtools, + YaccKind: Grmtools, lrpar.recoverer: CPCTPlus, - test.flag, - !test.negative, + test.Flag, + !test.Negative, test.string: "Foo", test.vec: ["Aaaa", "Bbbb"], test.num: 1234, @@ -1021,9 +1021,9 @@ start -> () : "a" {$;;;; }; start -> () : "a" { () }; "#; let ast_validity = ASTWithValidityInfo::from_str(src).unwrap(); - let test_flag_span = src.find_span("test.flag"); - let test_neg_span = src.find_span("test.negative"); - let test_neg_val_span = src.find_span("!test.negative"); + let test_flag_span = src.find_span("test.Flag"); + let test_neg_span = src.find_span("test.Negative"); + let test_neg_val_span = src.find_span("!test.Negative"); let test_string_span = src.find_span("test.string"); let test_string_val_span = src.find_span("Foo"); let test_vec_span = src.find_span("test.vec"); @@ -1034,6 +1034,7 @@ start -> () : "a" { () }; let test_num_val_span = src.find_span("1234"); let mut test_crate_expected = HashMap::new(); test_crate_expected.insert( + // Note the case difference. "test.flag".to_string(), ( test_flag_span, @@ -1041,6 +1042,7 @@ start -> () : "a" { () }; ), ); test_crate_expected.insert( + // Note the case difference. "test.negative".to_string(), ( test_neg_span, @@ -1082,7 +1084,7 @@ start -> () : "a" { () }; assert_eq!(test_crate_parsed, test_crate_expected); let mut cfgrammar_crate_expected = HashMap::new(); - let yacckind_span = src.find_span("yacckind"); + let yacckind_span = src.find_span("YaccKind"); let yacckind_val_span = src.find_span("Grmtools"); cfgrammar_crate_expected.insert( "cfgrammar.yacckind".to_string(), @@ -1228,6 +1230,7 @@ start: "a" { () }; } impl FindSpan for &'_ str { + #[track_caller] fn find_span(&self, s: &str) -> Span { let start_pos = self.find(s).unwrap(); Span::new(start_pos, start_pos + s.len()) From e3a4c7155d0e3c9d6f6222236f645bedcfd306a4 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 05:29:49 -0700 Subject: [PATCH 08/10] Make grmtools section case sensitive --- cfgrammar/src/lib/header.rs | 44 ++++++++++++------------- cfgrammar/src/lib/yacc/ast.rs | 24 +++++--------- cfgrammar/src/lib/yacc/grammar.rs | 4 +-- lrlex/src/lib/ctbuilder.rs | 6 ++-- lrpar/cttests/src/grmtools_section.test | 12 +++---- lrpar/src/lib/ctbuilder.rs | 14 ++++---- lrpar/src/lib/parser.rs | 10 +++--- nimbleparse/src/main.rs | 14 ++++---- 8 files changed, 60 insertions(+), 68 deletions(-) diff --git a/cfgrammar/src/lib/header.rs b/cfgrammar/src/lib/header.rs index e753d86a3..7cdbe0b5a 100644 --- a/cfgrammar/src/lib/header.rs +++ b/cfgrammar/src/lib/header.rs @@ -629,7 +629,7 @@ impl<'input> GrmtoolsSectionParser<'input> { Some(m) => { assert_eq!(m.start(), 0); Ok(( - self.src[i..i + m.end()].to_string().to_lowercase(), + self.src[i..i + m.end()].to_string(), i + m.end(), )) } @@ -678,30 +678,30 @@ impl TryFrom for Value { let from_loc = Location::Other("From".to_string()); Ok(match kind { YaccKind::Grmtools => Value::Setting(Setting::Unitary(Namespaced { - namespace: Some(("yacckind".to_string(), from_loc.clone())), - member: ("grmtools".to_string(), from_loc), + namespace: Some(("YaccKind".to_string(), from_loc.clone())), + member: ("Grmtools".to_string(), from_loc), })), YaccKind::Eco => Value::Setting(Setting::Unitary(Namespaced { - namespace: Some(("yacckind".to_string(), from_loc.clone())), - member: ("eco".to_string(), from_loc), + namespace: Some(("YaccKind".to_string(), from_loc.clone())), + member: ("Eco".to_string(), from_loc), })), YaccKind::Original(action_kind) => Value::Setting(Setting::Constructor { ctor: Namespaced { - namespace: Some(("yacckind".to_string(), from_loc.clone())), - member: ("original".to_string(), from_loc.clone()), + namespace: Some(("YaccKind".to_string(), from_loc.clone())), + member: ("Original".to_string(), from_loc.clone()), }, arg: match action_kind { YaccOriginalActionKind::NoAction => Namespaced { - namespace: Some(("yaccoriginalactionkind".to_string(), from_loc.clone())), - member: ("noaction".to_string(), from_loc), + namespace: Some(("YaccOriginalActionKind".to_string(), from_loc.clone())), + member: ("NoAction".to_string(), from_loc), }, YaccOriginalActionKind::UserAction => Namespaced { - namespace: Some(("yaccoriginalactionkind".to_string(), from_loc.clone())), - member: ("useraction".to_string(), from_loc), + namespace: Some(("YaccOriginalActionKind".to_string(), from_loc.clone())), + member: ("UserAction".to_string(), from_loc), }, YaccOriginalActionKind::GenericParseTree => Namespaced { - namespace: Some(("yaccoriginalactionkind".to_string(), from_loc.clone())), - member: ("genericparsetree".to_string(), from_loc), + namespace: Some(("YaccOriginalActionKind".to_string(), from_loc.clone())), + member: ("GenericParseTree".to_string(), from_loc), }, }, }), @@ -719,13 +719,13 @@ impl TryFrom<&Value> for YaccKind { member: (yk_value, yk_value_loc), })) => { if let Some((ns, ns_loc)) = namespace - && ns != "yacckind" + && ns != "YaccKind" { err_locs.push(ns_loc.clone()); } let yacckinds = [ - ("grmtools".to_string(), YaccKind::Grmtools), - ("eco".to_string(), YaccKind::Eco), + ("Grmtools".to_string(), YaccKind::Grmtools), + ("Eco".to_string(), YaccKind::Eco), ]; let yk_found = yacckinds .iter() @@ -760,24 +760,24 @@ impl TryFrom<&Value> for YaccKind { }, }) => { if let Some((yk_ns, yk_ns_loc)) = yk_namespace - && yk_ns != "yacckind" + && yk_ns != "YaccKind" { err_locs.push(yk_ns_loc.clone()); } - if yk_str != "original" { + if yk_str != "Original" { err_locs.push(yk_loc.clone()); } if let Some((ak_ns, ak_ns_loc)) = ak_namespace - && ak_ns != "yaccoriginalactionkind" + && ak_ns != "YaccOriginalActionKind" { err_locs.push(ak_ns_loc.clone()); } let actionkinds = [ - ("noaction", YaccOriginalActionKind::NoAction), - ("useraction", YaccOriginalActionKind::UserAction), - ("genericparsetree", YaccOriginalActionKind::GenericParseTree), + ("NoAction", YaccOriginalActionKind::NoAction), + ("UserAction", YaccOriginalActionKind::UserAction), + ("GenericParseTree", YaccOriginalActionKind::GenericParseTree), ]; let yk_found = actionkinds.iter().find_map(|(actionkind_str, actionkind)| { (ak_str == actionkind_str).then_some(YaccKind::Original(*actionkind)) diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index d294645e3..d5777d2a2 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -1008,7 +1008,7 @@ start -> () : "a" {$;;;; }; use super::*; let src = r#" %grmtools { - YaccKind: Grmtools, + yacckind: Grmtools, lrpar.recoverer: CPCTPlus, test.Flag, !test.Negative, @@ -1034,16 +1034,14 @@ start -> () : "a" { () }; let test_num_val_span = src.find_span("1234"); let mut test_crate_expected = HashMap::new(); test_crate_expected.insert( - // Note the case difference. - "test.flag".to_string(), + "test.Flag".to_string(), ( test_flag_span, GrmtoolsSectionValue::Bool(true, test_flag_span), ), ); test_crate_expected.insert( - // Note the case difference. - "test.negative".to_string(), + "test.Negative".to_string(), ( test_neg_span, GrmtoolsSectionValue::Bool(false, test_neg_val_span), @@ -1084,14 +1082,14 @@ start -> () : "a" { () }; assert_eq!(test_crate_parsed, test_crate_expected); let mut cfgrammar_crate_expected = HashMap::new(); - let yacckind_span = src.find_span("YaccKind"); + let yacckind_span = src.find_span("yacckind"); let yacckind_val_span = src.find_span("Grmtools"); cfgrammar_crate_expected.insert( "cfgrammar.yacckind".to_string(), ( yacckind_span, // The actual value we receive has been lower cased - GrmtoolsSectionValue::RustLike("grmtools".to_string(), yacckind_val_span), + GrmtoolsSectionValue::RustLike("Grmtools".to_string(), yacckind_val_span), ), ); let cfgrammar_crate_parsed = ast_validity @@ -1108,8 +1106,7 @@ start -> () : "a" { () }; "lrpar.recoverer".to_string(), ( recoverer_span, - // The actual value we receive has been lower cased - GrmtoolsSectionValue::RustLike("cpctplus".to_string(), recoverer_val_span), + GrmtoolsSectionValue::RustLike("CPCTPlus".to_string(), recoverer_val_span), ), ); let lrpar_crate_parsed = ast_validity @@ -1140,9 +1137,8 @@ start: "a" { () }; "cfgrammar.yacckind".to_string(), ( yacckind_span, - // The actual value we receive has been lower cased GrmtoolsSectionValue::RustLike( - "original(yaccoriginalactionkind::useraction)".to_string(), + "Original(YaccOriginalActionKind::UserAction)".to_string(), yacckind_val_span, ), ), @@ -1175,9 +1171,8 @@ start: "a" { () }; "cfgrammar.yacckind".to_string(), ( yacckind_span, - // The actual value we receive has been lower cased GrmtoolsSectionValue::RustLike( - "yacckind::original(yaccoriginalactionkind::useraction)".to_string(), + "YaccKind::Original(YaccOriginalActionKind::UserAction)".to_string(), yacckind_val_span, ), ), @@ -1210,9 +1205,8 @@ start: "a" { () }; "cfgrammar.yacckind".to_string(), ( yacckind_span, - // The actual value we receive has been lower cased GrmtoolsSectionValue::RustLike( - "yacckind::original(useraction)".to_string(), + "YaccKind::Original(UserAction)".to_string(), yacckind_val_span, ), ), diff --git a/cfgrammar/src/lib/yacc/grammar.rs b/cfgrammar/src/lib/yacc/grammar.rs index a03010ee7..cd2eab3e5 100644 --- a/cfgrammar/src/lib/yacc/grammar.rs +++ b/cfgrammar/src/lib/yacc/grammar.rs @@ -1570,11 +1570,11 @@ mod test { "%grmtools{yacckind: YaccKind::Original(GenericParseTree)} %% Start: ;", - "%grmtools{yacckind: YaccKind::Original(yaccoriginalactionkind::useraction)} + "%grmtools{yacckind: YaccKind::Original(YaccOriginalActionKind::UserAction)} %actiontype () %% Start: {};", - "%grmtools{yacckind: Original(YACCOriginalActionKind::NoAction)} + "%grmtools{yacckind: Original(YaccOriginalActionKind::NoAction)} %% Start: ;", "%grmtools{yacckind: YaccKind::Grmtools} diff --git a/lrlex/src/lib/ctbuilder.rs b/lrlex/src/lib/ctbuilder.rs index 58cad2a37..071332c65 100644 --- a/lrlex/src/lib/ctbuilder.rs +++ b/lrlex/src/lib/ctbuilder.rs @@ -98,7 +98,7 @@ impl TryFrom<&Value> for LexerKind { member: (member, member_loc), })) => { if let Some((ns, loc)) = namespace - && ns.to_lowercase() != "lexerkind" + && ns != "LexerKind" { return Err(HeaderError { kind: HeaderErrorKind::ConversionError( @@ -1286,9 +1286,7 @@ mod test { fn test_grmtools_section_lexerkind() { let lexerkinds = [ "LRNonStreamingLexer", - "lrnonstreaminglexer", - "LexerKind::lrnonstreaminglexer", - "lexerkind::LRNonStreamingLexer", + "LexerKind::LRNonStreamingLexer", ]; for (i, kind) in lexerkinds.iter().enumerate() { let lex_src = format!( diff --git a/lrpar/cttests/src/grmtools_section.test b/lrpar/cttests/src/grmtools_section.test index c0cd4962b..5a2e97405 100644 --- a/lrpar/cttests/src/grmtools_section.test +++ b/lrpar/cttests/src/grmtools_section.test @@ -78,7 +78,7 @@ grammar: | namespaced -> Namespaced : IDENT { let ident_span = $1.as_ref().unwrap().span(); - let ident = $lexer.span_str(ident_span).to_string().to_lowercase(); + let ident = $lexer.span_str(ident_span).to_string(); Namespaced{ namespace: None, member: (ident, ident_span) @@ -86,10 +86,10 @@ grammar: | } | IDENT '::' IDENT { let namespace_span = $1.as_ref().unwrap().span(); - let namespace = $lexer.span_str(namespace_span).to_string().to_lowercase(); + let namespace = $lexer.span_str(namespace_span).to_string(); let ident_span = $3.as_ref().unwrap().span(); - let ident = $lexer.span_str(ident_span).to_string().to_lowercase(); + let ident = $lexer.span_str(ident_span).to_string(); Namespaced { namespace: Some((namespace, namespace_span)), member: (ident, ident_span) @@ -100,18 +100,18 @@ grammar: | valbind -> ((String, Span), Value) : IDENT ':' val { let key_span = $1.as_ref().unwrap().span(); - let key = $lexer.span_str(key_span).to_string().to_lowercase(); + let key = $lexer.span_str(key_span).to_string(); ((key, key_span), Value::Setting($3)) } | IDENT { let key_span = $1.as_ref().unwrap().span(); - let key = $lexer.span_str(key_span).to_string().to_lowercase(); + let key = $lexer.span_str(key_span).to_string(); ((key, key_span), Value::Flag(true, key_span)) } | '!' IDENT { let bang_span = $1.as_ref().unwrap().span(); let key_span = $2.as_ref().unwrap().span(); - let key = $lexer.span_str(key_span).to_string().to_lowercase(); + let key = $lexer.span_str(key_span).to_string(); ((key, key_span), Value::Flag(false, Span::new(bang_span.start(), key_span.end()))) } ; diff --git a/lrpar/src/lib/ctbuilder.rs b/lrpar/src/lib/ctbuilder.rs index 6aacc1913..79e82d94f 100644 --- a/lrpar/src/lib/ctbuilder.rs +++ b/lrpar/src/lib/ctbuilder.rs @@ -141,13 +141,13 @@ impl TryFrom for Value { let from_loc = Location::Other("From".to_string()); Ok(match kind { SerialisationFormat::FixedSizeInteger => Value::Setting(Setting::Unitary(Namespaced { - namespace: Some(("serialisationformat".to_string(), from_loc.clone())), - member: ("fixedsizeinteger".to_string(), from_loc), + namespace: Some(("SerialisationFormat".to_string(), from_loc.clone())), + member: ("FixedSizeInteger".to_string(), from_loc), })), SerialisationFormat::VariableSizedInteger => { Value::Setting(Setting::Unitary(Namespaced { - namespace: Some(("serialisationformat".to_string(), from_loc.clone())), - member: ("variablesizedinteger".to_string(), from_loc), + namespace: Some(("SerialisationFormat".to_string(), from_loc.clone())), + member: ("VariableSizedInteger".to_string(), from_loc), })) } }) @@ -165,17 +165,17 @@ impl TryFrom<&Value> for SerialisationFormat { member: (enc_value, enc_value_loc), })) => { if let Some((ns, ns_loc)) = namespace - && ns != "serialisationformat" + && ns != "SerialisationFormat" { err_locs.push(ns_loc.clone()); } let encodings = [ ( - "fixedsizeinteger".to_string(), + "FixedSizeInteger".to_string(), SerialisationFormat::FixedSizeInteger, ), ( - "variablesizedinteger".to_string(), + "VariableSizedInteger".to_string(), SerialisationFormat::VariableSizedInteger, ), ]; diff --git a/lrpar/src/lib/parser.rs b/lrpar/src/lib/parser.rs index 959021343..c49bdb732 100644 --- a/lrpar/src/lib/parser.rs +++ b/lrpar/src/lib/parser.rs @@ -667,7 +667,7 @@ impl TryFrom<&Value> for RecoveryKind { member: (kind, kind_loc), })) => { match namespace { - Some((ns, loc)) if ns.to_lowercase() != "recoverykind" => { + Some((ns, loc)) if ns != "RecoveryKind" => { return Err(HeaderError { kind: HeaderErrorKind::ConversionError( "RecoveryKind", @@ -678,9 +678,9 @@ impl TryFrom<&Value> for RecoveryKind { } _ => {} } - match kind.to_lowercase().as_ref() { - "cpctplus" => Ok(RecoveryKind::CPCTPlus), - "none" => Ok(RecoveryKind::None), + match kind.as_ref() { + "CPCTPlus" => Ok(RecoveryKind::CPCTPlus), + "None" => Ok(RecoveryKind::None), _ => Err(HeaderError { kind: HeaderErrorKind::ConversionError("RecoveryKind", "Unknown variant"), locations: vec![kind_loc.clone()], @@ -1367,7 +1367,7 @@ Call: 'ID' '(' ')';"; \* '*' "#; let grammar_src = " -%grmtools{YaccKind: Original(NoAction)} +%grmtools{yacckind: Original(NoAction)} %start Expr %% Expr : Expr '+' Term | Term; diff --git a/nimbleparse/src/main.rs b/nimbleparse/src/main.rs index e7feb8958..775e9a554 100644 --- a/nimbleparse/src/main.rs +++ b/nimbleparse/src/main.rs @@ -185,9 +185,9 @@ fn main() { "lrpar.recoverer".to_string(), HeaderValue( Location::CommandLine, - Value::try_from(match &*s.to_lowercase() { - "cpctplus" => RecoveryKind::CPCTPlus, - "none" => RecoveryKind::None, + Value::try_from(match &*s { + "CPCTPlus" => RecoveryKind::CPCTPlus, + "None" => RecoveryKind::None, _ => usage(prog, &format!("Unknown recoverer '{}'.", s)), }) .expect("All these RecoveryKinds should convert without error"), @@ -204,10 +204,10 @@ fn main() { Some(s) => { entry.insert_entry(HeaderValue( Location::CommandLine, - Value::try_from(match &*s.to_lowercase() { - "eco" => YaccKind::Eco, - "grmtools" => YaccKind::Grmtools, - "original" => YaccKind::Original(YaccOriginalActionKind::GenericParseTree), + Value::try_from(match &*s { + "Eco" => YaccKind::Eco, + "Grmtools" => YaccKind::Grmtools, + "Original" => YaccKind::Original(YaccOriginalActionKind::GenericParseTree), _ => usage(prog, &format!("Unknown Yacc variant '{}'.", s)), }) .expect("All these yacckinds should convert without error"), From c52fd9db916fec305be6c2e8fee7f33b32ebead9 Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 05:30:17 -0700 Subject: [PATCH 09/10] rustfmt --- cfgrammar/src/lib/header.rs | 5 +---- cfgrammar/src/lib/yacc/ast.rs | 5 +++-- lrlex/src/lib/ctbuilder.rs | 5 +---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/cfgrammar/src/lib/header.rs b/cfgrammar/src/lib/header.rs index 7cdbe0b5a..cb0527fcf 100644 --- a/cfgrammar/src/lib/header.rs +++ b/cfgrammar/src/lib/header.rs @@ -628,10 +628,7 @@ impl<'input> GrmtoolsSectionParser<'input> { match RE_NAME.find(&self.src[i..]) { Some(m) => { assert_eq!(m.start(), 0); - Ok(( - self.src[i..i + m.end()].to_string(), - i + m.end(), - )) + Ok((self.src[i..i + m.end()].to_string(), i + m.end())) } None => { if self.src[i..].starts_with("*") { diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index d5777d2a2..1ed3a589d 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -1166,7 +1166,8 @@ start: "a" { () }; let ast_validity = ASTWithValidityInfo::from_str(src).unwrap(); let mut cfgrammar_crate_expected = HashMap::new(); let yacckind_span = src.find_span("yacckind"); - let yacckind_val_span = src.find_span("YaccKind::Original(YaccOriginalActionKind::UserAction)"); + let yacckind_val_span = + src.find_span("YaccKind::Original(YaccOriginalActionKind::UserAction)"); cfgrammar_crate_expected.insert( "cfgrammar.yacckind".to_string(), ( @@ -1185,7 +1186,7 @@ start: "a" { () }; assert_eq!(cfgrammar_crate_parsed, cfgrammar_crate_expected); } - #[test] + #[test] fn test_grmtools_section_values4() { use super::*; let src = r#" diff --git a/lrlex/src/lib/ctbuilder.rs b/lrlex/src/lib/ctbuilder.rs index 071332c65..5ca2e1cca 100644 --- a/lrlex/src/lib/ctbuilder.rs +++ b/lrlex/src/lib/ctbuilder.rs @@ -1284,10 +1284,7 @@ mod test { use super::{CTLexerBuilder, LexerKind}; #[test] fn test_grmtools_section_lexerkind() { - let lexerkinds = [ - "LRNonStreamingLexer", - "LexerKind::LRNonStreamingLexer", - ]; + let lexerkinds = ["LRNonStreamingLexer", "LexerKind::LRNonStreamingLexer"]; for (i, kind) in lexerkinds.iter().enumerate() { let lex_src = format!( " From 065ad66832458ea09b431b94201c0a1db653878b Mon Sep 17 00:00:00 2001 From: matt rice Date: Thu, 27 Aug 2026 05:45:28 -0700 Subject: [PATCH 10/10] Combine grmtools_section_values with the for_crate version --- cfgrammar/src/lib/yacc/ast.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cfgrammar/src/lib/yacc/ast.rs b/cfgrammar/src/lib/yacc/ast.rs index 1ed3a589d..2e701550e 100644 --- a/cfgrammar/src/lib/yacc/ast.rs +++ b/cfgrammar/src/lib/yacc/ast.rs @@ -548,18 +548,19 @@ impl GrammarAST { ) } - pub fn grmtools_section_values( - &self, - ) -> impl Iterator { - self.grmtools_section.iter() - } - + /// Returns the entries from the grmtools section with keys that are prefixed with the `crate_name` + /// followed by a dot. If `crate_name` is empty returns all entries for all crates. pub fn grmtools_section_values_for_crate( &self, crate_name: &str, ) -> impl Iterator { - self.grmtools_section_values() - .filter(move |(key, _)| key.starts_with(&format!("{crate_name}."))) + self.grmtools_section.iter().filter(move |(key, _)| { + if !crate_name.is_empty() { + key.starts_with(&format!("{crate_name}.")) + } else { + true + } + }) } }