diff --git a/cfgrammar/src/lib/header.rs b/cfgrammar/src/lib/header.rs index fcd8963ea..a45b5c327 100644 --- a/cfgrammar/src/lib/header.rs +++ b/cfgrammar/src/lib/header.rs @@ -50,7 +50,7 @@ impl Spanned for HeaderError { // Thus we aren't worried about it being `pub`. #[derive(Debug, PartialEq)] #[doc(hidden)] -pub struct HeaderValue(pub T, pub Value); +pub struct HeaderValue(pub T, pub GrmtoolsSectionValue); impl From> for HeaderValue { fn from(hv: HeaderValue) -> HeaderValue { @@ -90,57 +90,6 @@ impl fmt::Display for HeaderErrorKind { } } -impl HeaderError { - /// Returns the [SpansKind] associated with this error. - pub fn spanskind(&self) -> SpansKind { - match self.kind { - HeaderErrorKind::DuplicateEntry => SpansKind::DuplicationError, - _ => SpansKind::Error, - } - } -} - -/// Indicates a value prefixed by an optional namespace. -/// `Foo::Bar` with optional `Foo` specified being -/// ```rust,ignore -/// Namespaced{ -/// namespace: Some(("Foo", ...)), -/// member: ("Bar", ...) -/// } -/// ``` -/// -/// Alternately just `Bar` alone without a namespace is represented by : -/// ```rust,ignore -/// Namespaced{ -/// namespace: None, -/// member: ("Bar", ...) -/// } -/// ``` -#[derive(Debug, Eq, PartialEq)] -#[doc(hidden)] -pub struct Namespaced { - pub namespace: Option<(String, T)>, - pub member: (String, T), -} - -#[derive(Debug, Eq, PartialEq)] -#[doc(hidden)] -pub enum Setting { - /// A value like `YaccKind::Grmtools` - Unitary(Namespaced), - /// A value like `YaccKind::Original(UserActions)`. - /// In that example the field ctor would be: `Namespaced { namespace: "YaccKind", member: "Original" }`. - /// The field would be `Namespaced{ None, UserActions }`. - Constructor { - ctor: Namespaced, - arg: Namespaced, - }, - Num(u64, T), - String(String, T), - // The two `T` values are for the spans of the open and close brackets `[`, and `]`. - Array(Vec>, T, T), -} - /// Parser for the `%grmtools` section #[doc(hidden)] pub struct GrmtoolsSectionParser<'input> { @@ -148,94 +97,41 @@ pub struct GrmtoolsSectionParser<'input> { required: bool, } -/// The value contained within a `Header` -/// -/// 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)] -#[doc(hidden)] -pub enum Value { - Flag(bool, T), - Setting(Setting), +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub enum GrmtoolsSectionValue { + String(String, T), + Num(u64, T), + Bool(bool, T), + Array(Vec>, T), + RustLike(String, T), } -impl From> for Setting { - fn from(s: Setting) -> Setting { - match s { - Setting::Unitary(Namespaced { - namespace, - member: (m, ml), - }) => Setting::Unitary(Namespaced { - namespace: namespace.map(|(n, nl)| (n, nl.into())), - member: (m, ml.into()), - }), - Setting::Constructor { - ctor: - Namespaced { - namespace: ctor_ns, - member: (ctor_m, ctor_ml), - }, - arg: - Namespaced { - namespace: arg_ns, - member: (arg_m, arg_ml), - }, - } => Setting::Constructor { - ctor: Namespaced { - namespace: ctor_ns.map(|(ns, ns_l)| (ns, ns_l.into())), - member: (ctor_m, ctor_ml.into()), - }, - arg: Namespaced { - namespace: arg_ns.map(|(ns, ns_l)| (ns, ns_l.into())), - member: (arg_m, arg_ml.into()), - }, - }, - Setting::Num(num, num_loc) => Setting::Num(num, num_loc.into()), - Setting::String(s, str_loc) => Setting::String(s, str_loc.into()), - Setting::Array(mut xs, arr_open_loc, arr_close_loc) => Setting::Array( - xs.drain(..).map(|x| x.into()).collect(), - arr_open_loc.into(), - arr_close_loc.into(), +impl From> for GrmtoolsSectionValue { + fn from(it: GrmtoolsSectionValue) -> GrmtoolsSectionValue { + use GrmtoolsSectionValue as GV; + match it { + GV::String(v, span) => GV::String(v, Location::Span(span)), + GV::Num(v, span) => GV::Num(v, Location::Span(span)), + GV::Bool(v, span) => GV::Bool(v, Location::Span(span)), + GV::Array(mut v, span) => GV::Array( + v.drain(..).map(|val| val.into()).collect::>(), + Location::Span(span), ), + GV::RustLike(v, span) => GV::RustLike(v, Location::Span(span)), } } } -impl From> for Value { - fn from(v: Value) -> Value { - match v { - Value::Flag(flag, u) => Value::Flag(flag, u.into()), - Value::Setting(s) => Value::Setting(s.into()), - } - } -} - -impl Value { - pub fn primary_location(&self) -> &T { - match self { - Value::Flag(_, loc) => loc, - Value::Setting(setting) => setting.primary_location(), - } - } -} - -impl Setting { - fn primary_location(&self) -> &T { - match self { - Self::Constructor { arg, .. } => arg.primary_location(), - Self::Unitary(ns) => ns.primary_location(), - Self::Array(_, start_loc, _) => start_loc, - Self::Num(_, loc) | Self::String(_, loc) => loc, +impl HeaderError { + /// Returns the [SpansKind] associated with this error. + pub fn spanskind(&self) -> SpansKind { + match self.kind { + HeaderErrorKind::DuplicateEntry => SpansKind::DuplicationError, + _ => SpansKind::Error, } } } -impl Namespaced { - fn primary_location(&self) -> &T { - &self.member.1 - } -} - static RE_LEADING_WS: LazyLock = LazyLock::new(|| Regex::new(r"^[\p{Pattern_White_Space}]*").unwrap()); static RE_NAME: LazyLock = LazyLock::new(|| { @@ -311,7 +207,10 @@ fn add_duplicate_occurrence( } impl<'input> GrmtoolsSectionParser<'input> { - fn parse_setting(&'_ self, mut i: usize) -> Result<(Setting, usize), HeaderError> { + fn parse_value( + &'_ self, + mut i: usize, + ) -> Result<(GrmtoolsSectionValue, usize), HeaderError> { i = self.parse_ws(i); match RE_DIGITS.find(&self.src[i..]) { Some(m) => { @@ -319,7 +218,7 @@ impl<'input> GrmtoolsSectionParser<'input> { let num_str = &self.src[num_span.start()..num_span.end()]; // If the above regex matches we expect this to succeed. let num = str::parse::(num_str).unwrap(); - let val = Setting::Num(num, num_span); + let val = GrmtoolsSectionValue::Num(num, num_span); i = self.parse_ws(num_span.end()); Ok((val, i)) } @@ -329,7 +228,7 @@ impl<'input> GrmtoolsSectionParser<'input> { // Trim the leading and trailing quotes. let str_span = Span::new(i + m.start() + 1, end - 1); let str = &self.src[str_span.start()..str_span.end()]; - let setting = Setting::String(str.to_string(), str_span); + let setting = GrmtoolsSectionValue::String(str.to_string(), str_span); // After the trailing quotes. i = self.parse_ws(end); Ok((setting, i)) @@ -337,21 +236,15 @@ impl<'input> GrmtoolsSectionParser<'input> { None => { if let Some(mut j) = self.lookahead_is("[", i) { let mut vals = Vec::new(); - let open_pos = j; - loop { j = self.parse_ws(j); if let Some(end_pos) = self.lookahead_is("]", j) { return Ok(( - Setting::Array( - vals, - Span::new(i, open_pos), - Span::new(j, end_pos), - ), + GrmtoolsSectionValue::Array(vals, Span::new(i, end_pos)), end_pos, )); } - if let Ok((val, k)) = self.parse_setting(j) { + if let Ok((val, k)) = self.parse_value(j) { vals.push(val); j = self.parse_ws(k); } @@ -360,18 +253,19 @@ impl<'input> GrmtoolsSectionParser<'input> { } } } else { - let (path_val, j) = self.parse_namespaced(i)?; + let ((path_val, path_span), j) = self.parse_rustlike(i)?; i = self.parse_ws(j); if let Some(j) = self.lookahead_is("(", i) { - let (arg, j) = self.parse_namespaced(j)?; + let ((arg, _), j) = self.parse_rustlike(j)?; i = self.parse_ws(j); if let Some(j) = self.lookahead_is(")", i) { i = self.parse_ws(j); + let span = Span::new(path_span.start(), j); Ok(( - Setting::Constructor { - ctor: path_val, - arg, - }, + (GrmtoolsSectionValue::RustLike( + format!("{path_val}({arg})"), + span, + )), i, )) } else { @@ -381,7 +275,7 @@ impl<'input> GrmtoolsSectionParser<'input> { }) } } else { - Ok((Setting::Unitary(path_val), i)) + Ok((GrmtoolsSectionValue::RustLike(path_val, path_span), i)) } } } @@ -392,13 +286,13 @@ impl<'input> GrmtoolsSectionParser<'input> { pub fn parse_key_value( &'_ self, mut i: usize, - ) -> Result<(String, Span, Value, usize), HeaderError> { + ) -> Result<(String, Span, GrmtoolsSectionValue, usize), HeaderError> { if let Some(j) = self.lookahead_is("!", i) { let (flag_name, k) = self.parse_name(j)?; Ok(( flag_name, Span::new(j, k), - Value::Flag(false, Span::new(i, k)), + GrmtoolsSectionValue::Bool(false, Span::new(i, k)), self.parse_ws(k), )) } else { @@ -406,19 +300,21 @@ impl<'input> GrmtoolsSectionParser<'input> { let key_span = Span::new(i, j); i = self.parse_ws(j); if let Some(j) = self.lookahead_is(":", i) { - let (val, j) = self.parse_setting(j)?; - Ok((key_name, key_span, Value::Setting(val), j)) + let (val, j) = self.parse_value(j)?; + Ok((key_name, key_span, val, j)) } else { - Ok((key_name, key_span, Value::Flag(true, key_span), i)) + Ok(( + key_name, + key_span, + GrmtoolsSectionValue::Bool(true, key_span), + i, + )) } } } - fn parse_namespaced( - &self, - mut i: usize, - ) -> Result<(Namespaced, usize), HeaderError> { - // Either a name alone, or a namespace which will be followed by a member. + fn parse_rustlike(&self, mut i: usize) -> Result<((String, Span), usize), HeaderError> { + // Either a name alone, or a type::name. let (name, j) = self.parse_name(i)?; let name_span = Span::new(i, j); i = self.parse_ws(j); @@ -427,21 +323,10 @@ impl<'input> GrmtoolsSectionParser<'input> { let (member_val, j) = self.parse_name(i)?; let member_val_span = Span::new(i, j); i = self.parse_ws(j); - Ok(( - Namespaced { - namespace: Some((name, name_span)), - member: (member_val, member_val_span), - }, - i, - )) + let span = Span::new(name_span.start(), member_val_span.end()); + Ok(((format!("{name}::{member_val}"), span), i)) } else { - Ok(( - Namespaced { - namespace: None, - member: (name, name_span), - }, - i, - )) + Ok(((name, name_span), i)) } } @@ -552,10 +437,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().to_lowercase(), - i + m.end(), - )) + Ok((self.src[i..i + m.end()].to_string(), i + m.end())) } None => { if self.src[i..].starts_with("*") { @@ -596,142 +478,68 @@ impl<'input> GrmtoolsSectionParser<'input> { #[doc(hidden)] pub type Header = MarkMap>; -impl TryFrom for Value { +impl TryFrom for GrmtoolsSectionValue { type Error = HeaderError; - fn try_from(kind: YaccKind) -> Result, HeaderError> { + fn try_from(kind: YaccKind) -> Result, HeaderError> { 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), - })), - YaccKind::Eco => Value::Setting(Setting::Unitary(Namespaced { - 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()), - }, - arg: match action_kind { - YaccOriginalActionKind::NoAction => Namespaced { - 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), - }, - YaccOriginalActionKind::GenericParseTree => Namespaced { - namespace: Some(("yaccoriginalactionkind".to_string(), from_loc.clone())), - member: ("genericparsetree".to_string(), from_loc), - }, - }, - }), - }) + Ok(GrmtoolsSectionValue::RustLike( + format!("YaccKind::{kind:?}"), + from_loc, + )) } } -impl TryFrom<&Value> for YaccKind { +impl TryFrom<&GrmtoolsSectionValue> for YaccKind { type Error = HeaderError; - fn try_from(value: &Value) -> Result> { - let mut err_locs = Vec::new(); + fn try_from(value: &GrmtoolsSectionValue) -> Result> { match value { - Value::Setting(Setting::Unitary(Namespaced { - namespace, - member: (yk_value, yk_value_loc), - })) => { - if let Some((ns, ns_loc)) = namespace - && ns != "yacckind" - { - err_locs.push(ns_loc.clone()); - } - let yacckinds = [ - ("grmtools".to_string(), YaccKind::Grmtools), - ("eco".to_string(), YaccKind::Eco), - ]; - let yk_found = yacckinds - .iter() - .find_map(|(yk_str, yk)| (yk_str == yk_value).then_some(yk)); - if let Some(yk) = yk_found { - if err_locs.is_empty() { - Ok(*yk) - } else { - Err(HeaderError { - kind: HeaderErrorKind::InvalidEntry("yacckind"), - locations: err_locs, - }) - } - } else { - err_locs.push(yk_value_loc.clone()); - Err(HeaderError { - kind: HeaderErrorKind::InvalidEntry("yacckind"), - locations: err_locs, - }) - } - } - Value::Setting(Setting::Constructor { - ctor: - Namespaced { - namespace: yk_namespace, - member: (yk_str, yk_loc), - }, - arg: - Namespaced { - namespace: ak_namespace, - member: (ak_str, ak_loc), - }, - }) => { - if let Some((yk_ns, yk_ns_loc)) = yk_namespace - && yk_ns != "yacckind" - { - err_locs.push(yk_ns_loc.clone()); + GrmtoolsSectionValue::RustLike(kind, loc) => match kind.as_str() { + "YaccKind::Grmtools" | "Grmtools" => Ok(YaccKind::Grmtools), + "YaccKind::Eco" | "Eco" => Ok(YaccKind::Eco), + "YaccKind::Original(UserAction)" + | "Original(UserAction)" + | "Original(YaccOriginalActionKind::UserAction)" + | "YaccKind::Original(YaccOriginalActionKind::UserAction)" => { + Ok(YaccKind::Original(YaccOriginalActionKind::UserAction)) } - - if yk_str != "original" { - err_locs.push(yk_loc.clone()); + "YaccKind::Original(NoAction)" + | "Original(NoAction)" + | "Original(YaccOriginalActionKind::NoAction)" + | "YaccKind::Original(YaccOriginalActionKind::NoAction)" => { + Ok(YaccKind::Original(YaccOriginalActionKind::NoAction)) } - - if let Some((ak_ns, ak_ns_loc)) = ak_namespace - && ak_ns != "yaccoriginalactionkind" - { - err_locs.push(ak_ns_loc.clone()); + "YaccKind::Original(GenericParseTree)" + | "Original(GenericParseTree)" + | "Original(YaccOriginalActionKind::GenericParseTree)" + | "YaccKind::Original(YaccOriginalActionKind::GenericParseTree)" => { + Ok(YaccKind::Original(YaccOriginalActionKind::GenericParseTree)) } - let actionkinds = [ - ("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)) - }); - - if let Some(yk) = yk_found { - if err_locs.is_empty() { - Ok(yk) - } else { - Err(HeaderError { - kind: HeaderErrorKind::InvalidEntry("yacckind"), - locations: err_locs, - }) - } - } else { - err_locs.push(ak_loc.clone()); - Err(HeaderError { - kind: HeaderErrorKind::InvalidEntry("yacckind"), - locations: err_locs, - }) - } - } + _ => Err(HeaderError { + kind: HeaderErrorKind::InvalidEntry("cfgrammar.yacckind"), + locations: vec![loc.clone()], + }), + }, val => Err(HeaderError { - kind: HeaderErrorKind::InvalidEntry("yacckind"), + kind: HeaderErrorKind::InvalidEntry("cfgrammar.yacckind"), locations: vec![val.primary_location().clone()], }), } } } +impl GrmtoolsSectionValue { + #[doc(hidden)] + pub fn primary_location(&self) -> &T { + match self { + Self::Array(_, loc) + | Self::Bool(_, loc) + | Self::Num(_, loc) + | Self::RustLike(_, loc) + | Self::String(_, loc) => loc, + } + } +} + #[cfg(test)] mod test { use super::*; 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..7c41af0ed 100644 --- a/lrlex/src/lib/ctbuilder.rs +++ b/lrlex/src/lib/ctbuilder.rs @@ -1,7 +1,7 @@ //! Build grammars at run-time. use cfgrammar::{ - header::{Header, HeaderError, HeaderErrorKind, HeaderValue, Namespaced, Setting, Value}, + header::{GrmtoolsSectionValue, Header, HeaderError, HeaderErrorKind, HeaderValue}, markmap::MergeBehavior, span::{Location, Span}, }; @@ -47,79 +47,23 @@ pub enum LexerKind { LRNonStreamingLexer, } -impl TryFrom<&Value> for LexerKind { +impl TryFrom<&GrmtoolsSectionValue> for LexerKind { type Error = cfgrammar::header::HeaderError; - fn try_from(it: &Value) -> Result { + fn try_from(it: &GrmtoolsSectionValue) -> Result { match it { - Value::Flag(_, loc) => Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Expected `LexerKind` found bool", - ), - locations: vec![loc.clone()], - }), - Value::Setting(Setting::Num(_, loc)) => Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Expected `LexerKind` found numeric", - ), - locations: vec![loc.clone()], - }), - Value::Setting(Setting::String(_, loc)) => Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Expected `LexerKind` found string", - ), - locations: vec![loc.clone()], - }), - Value::Setting(Setting::Constructor { - ctor: - Namespaced { - namespace: _, - member: (_, loc), - }, - arg: _, - }) => Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Expected `LexerKind` found constructor", - ), - locations: vec![loc.clone()], - }), - Value::Setting(Setting::Array(_, arr_loc, _)) => Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Expected `LexerKind` found array", - ), - locations: vec![arr_loc.clone()], - }), - Value::Setting(Setting::Unitary(Namespaced { - namespace, - member: (member, member_loc), - })) => { - if let Some((ns, loc)) = namespace - && ns.to_lowercase() != "lexerkind" - { - return Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Expected namespace `LexerKind`", - ), - locations: vec![loc.clone()], - }); - } - if member.to_lowercase() != "lrnonstreaminglexer" { - return Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "LexerKind", - "Unknown `LexerKind` Variant", - ), - locations: vec![member_loc.clone()], - }); + GrmtoolsSectionValue::RustLike(rs, loc) => match rs.as_str() { + "LexerKind::LRNonStreamingLexer" | "LRNonStreamingLexer" => { + Ok(LexerKind::LRNonStreamingLexer) } - - Ok(LexerKind::LRNonStreamingLexer) - } + _ => Err(HeaderError { + kind: HeaderErrorKind::ConversionError("LexerKind", "Expected `LexerKind`"), + locations: vec![loc.clone()], + }), + }, + val => Err(HeaderError { + kind: HeaderErrorKind::ConversionError("LexerKind", "Expected `LexerKind`"), + locations: vec![val.primary_location().clone()], + }), } } } @@ -516,10 +460,10 @@ where } }; match test_glob { - Some(HeaderValue(_, Value::Setting(Setting::Array(test_globs, _, _)))) => { + Some(HeaderValue(_, GrmtoolsSectionValue::Array(test_globs, _))) => { for setting in test_globs { match setting { - Setting::String(test_files, _) => { + GrmtoolsSectionValue::String(test_files, _) => { let path_joined = grm_path.parent().unwrap().join(test_files); let path_str = &path_joined.to_string_lossy(); let mut glob_paths = glob(path_str).map_err(|e| e.to_string())?.peekable(); @@ -846,7 +790,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -862,7 +806,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -878,7 +822,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -894,7 +838,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -910,7 +854,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -926,7 +870,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -942,7 +886,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -958,7 +902,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -974,7 +918,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Flag(flag, Location::Other("CTLexerBuilder".to_string())), + GrmtoolsSectionValue::Bool(flag, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -990,10 +934,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Setting(Setting::Num( - sz as u64, - Location::Other("CTLexerBuilder".to_string()), - )), + GrmtoolsSectionValue::Num(sz as u64, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -1009,10 +950,7 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Setting(Setting::Num( - sz as u64, - Location::Other("CTLexerBuilder".to_string()), - )), + GrmtoolsSectionValue::Num(sz as u64, Location::Other("CTLexerBuilder".to_string())), ), ); self @@ -1028,10 +966,10 @@ where key, HeaderValue( Location::Other("CTLexerBuilder".to_string()), - Value::Setting(Setting::Num( + GrmtoolsSectionValue::Num( lim as u64, Location::Other("CTLexerBuilder".to_string()), - )), + ), ), ); self @@ -1284,12 +1222,7 @@ mod test { use super::{CTLexerBuilder, LexerKind}; #[test] fn test_grmtools_section_lexerkind() { - let lexerkinds = [ - "LRNonStreamingLexer", - "lrnonstreaminglexer", - "LexerKind::lrnonstreaminglexer", - "lexerkind::LRNonStreamingLexer", - ]; + let lexerkinds = ["LRNonStreamingLexer", "LexerKind::LRNonStreamingLexer"]; for (i, kind) in lexerkinds.iter().enumerate() { let lex_src = format!( " diff --git a/lrlex/src/lib/lexer.rs b/lrlex/src/lib/lexer.rs index cc20e9c73..77bd38237 100644 --- a/lrlex/src/lib/lexer.rs +++ b/lrlex/src/lib/lexer.rs @@ -9,7 +9,10 @@ use std::{ use cfgrammar::{ NewlineCache, Span, - header::{GrmtoolsSectionParser, Header, HeaderError, HeaderErrorKind, HeaderValue, Value}, + header::{ + GrmtoolsSectionParser, GrmtoolsSectionValue, Header, HeaderError, HeaderErrorKind, + HeaderValue, + }, span::Location, }; use num_traits::{AsPrimitive, PrimInt, Unsigned}; @@ -47,7 +50,6 @@ pub struct LexFlags { impl TryFrom<&mut Header> for LexFlags { type Error = HeaderError; fn try_from(header: &mut Header) -> Result> { - use cfgrammar::header::Setting; let mut lex_flags = UNSPECIFIED_LEX_FLAGS; let LexFlags { dot_matches_new_line, @@ -67,10 +69,10 @@ impl TryFrom<&mut Header> for LexFlags { ($prefix:ident, $it:ident) => { header.mark_used(&stringify!($prefix.$it).to_string()); *$it = match header.get(stringify!($prefix.$it)) { - Some(HeaderValue(_, Value::Flag(flag, _))) => Some(*flag), - Some(HeaderValue(loc, _)) => Err(HeaderError { + Some(HeaderValue(_, GrmtoolsSectionValue::Bool(flag, _))) => Some(*flag), + Some(HeaderValue(_, val)) => Err(HeaderError { kind: HeaderErrorKind::ConversionError("LexFlags", "Expected boolean"), - locations: vec![loc.clone()], + locations: vec![val.primary_location().clone()], })?, None => None, } @@ -89,10 +91,10 @@ impl TryFrom<&mut Header> for LexFlags { ($prefix:ident, $it:ident, $num_ty: ty) => { header.mark_used(&stringify!($prefix.$it).to_string()); *$it = match header.get(stringify!($prefix.$it)) { - Some(HeaderValue(_, Value::Setting(Setting::Num(n, _)))) => Some(*n as $num_ty), - Some(HeaderValue(loc, _)) => Err(HeaderError { + Some(HeaderValue(_, GrmtoolsSectionValue::Num(n, _))) => Some(*n as $num_ty), + Some(HeaderValue(_, val)) => Err(HeaderError { kind: HeaderErrorKind::ConversionError("LexFlags", "Expected numeric"), - locations: vec![loc.clone()], + locations: vec![val.primary_location().clone()], })?, None => None, } @@ -128,8 +130,11 @@ impl From<&LexFlags> for Header { header.insert( stringify!($it).to_string(), HeaderValue( - Location::Other("From<&LexFlags".to_string()), - Value::Flag(x, Location::Other("From<&LexFlags>".to_string())), + Location::Other("From<&LexFlags>".to_string()), + GrmtoolsSectionValue::Bool( + x, + Location::Other("From<&LexFlags>".to_string()), + ), ), ) }); @@ -148,15 +153,14 @@ impl From<&LexFlags> for Header { macro_rules! cvt_num { ($it: ident) => { $it.map(|x| { - use cfgrammar::header::Setting; header.insert( stringify!($it).to_string(), HeaderValue( - Location::Other("From<&LexFlags".to_string()), - Value::Setting(Setting::Num( + Location::Other("From<&LexFlags>".to_string()), + GrmtoolsSectionValue::Num( x as u64, Location::Other("From<&LexFlags>".to_string()), - )), + ), ), ) }); diff --git a/lrpar/cttests/src/grmtools_section.test b/lrpar/cttests/src/grmtools_section.test index c0cd4962b..6a14cb510 100644 --- a/lrpar/cttests/src/grmtools_section.test +++ b/lrpar/cttests/src/grmtools_section.test @@ -75,66 +75,70 @@ grammar: | } ; - namespaced -> Namespaced + namespaced -> (String, Span) : IDENT { let ident_span = $1.as_ref().unwrap().span(); - let ident = $lexer.span_str(ident_span).to_string().to_lowercase(); - Namespaced{ - namespace: None, - member: (ident, ident_span) - } + let ident = $lexer.span_str(ident_span).to_string(); + (ident, ident_span) } | 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(); - Namespaced { - namespace: Some((namespace, namespace_span)), - member: (ident, ident_span) - } + let ident = $lexer.span_str(ident_span).to_string(); + let val = format!("{}::{}", namespace, ident); + let span = Span::new(namespace_span.start(), ident_span.end()); + (val, span) } ; - valbind -> ((String, Span), Value) + valbind -> ((String, Span), GrmtoolsSectionValue) : IDENT ':' val { let key_span = $1.as_ref().unwrap().span(); - let key = $lexer.span_str(key_span).to_string().to_lowercase(); - ((key, key_span), Value::Setting($3)) + let key = $lexer.span_str(key_span).to_string(); + ((key, key_span), $3) } | IDENT { let key_span = $1.as_ref().unwrap().span(); - let key = $lexer.span_str(key_span).to_string().to_lowercase(); - ((key, key_span), Value::Flag(true, key_span)) + let key = $lexer.span_str(key_span).to_string(); + ((key, key_span), GrmtoolsSectionValue::Bool(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(); - ((key, key_span), Value::Flag(false, Span::new(bang_span.start(), key_span.end()))) + let key = $lexer.span_str(key_span).to_string(); + ((key, key_span), GrmtoolsSectionValue::Bool(false, Span::new(bang_span.start(), key_span.end()))) } ; - val -> Setting - : namespaced { Setting::Unitary($1) } + val -> GrmtoolsSectionValue + : namespaced { GrmtoolsSectionValue::RustLike($1.0, $1.1) } | NUM { let num_span = $1.as_ref().unwrap().span(); let n = str::parse::($lexer.span_str(num_span)); - Setting::Num(n.expect("convertible"), num_span) + GrmtoolsSectionValue::Num(n.expect("convertible"), num_span) } | STRING { let string_span = $1.as_ref().unwrap().span(); // Trim the leading and trailing " characters. let string_span = Span::new(string_span.start() + 1, string_span.end() - 1); let s = $lexer.span_str(string_span).to_string(); - Setting::String(s, string_span) + GrmtoolsSectionValue::String(s, string_span) } - | namespaced '(' namespaced ')' { Setting::Constructor{ctor: $1, arg: $3} } - | '[' array_seq ']' { Setting::Array($2, $1.as_ref().unwrap().span(), $3.as_ref().unwrap().span()) } + | namespaced '(' namespaced ')' { + let span = Span::new($1.1.start(), $4.as_ref().unwrap().span().end()); + GrmtoolsSectionValue::RustLike(format!("{}({})", $1.0, $3.0), span) + } + | '[' array_seq ']' { + let open_span = $1.as_ref().unwrap().span(); + let close_span = $3.as_ref().unwrap().span(); + let span = Span::new(open_span.start(), close_span.end()); + GrmtoolsSectionValue::Array($2, span) + } ; - array_seq -> Vec> + array_seq -> Vec> : %empty { Vec::new() } | val { vec![$1] @@ -155,13 +159,11 @@ grammar: | use cfgrammar::{ Span, header::{ - Value, - Setting, + Header, HeaderError, HeaderErrorKind, - Namespaced, - Header, HeaderValue, + GrmtoolsSectionValue, CRATE_KEY_MAP, RE_CRATE_DOT, }, diff --git a/lrpar/src/lib/ctbuilder.rs b/lrpar/src/lib/ctbuilder.rs index 6aacc1913..a9183fb1b 100644 --- a/lrpar/src/lib/ctbuilder.rs +++ b/lrpar/src/lib/ctbuilder.rs @@ -27,7 +27,7 @@ use crate::unstable_api::UnstableApi; use cfgrammar::{ Location, - header::{Header, HeaderError, HeaderErrorKind, HeaderValue, Namespaced, Setting, Value}, + header::{GrmtoolsSectionValue, Header, HeaderError, HeaderErrorKind, HeaderValue}, markmap::{Entry, MergeBehavior}, yacc::{YaccGrammar, YaccKind, ast::ASTWithValidityInfo}, }; @@ -135,77 +135,41 @@ pub enum SerialisationFormat { VariableSizedInteger, } -impl TryFrom for Value { +impl TryFrom for GrmtoolsSectionValue { type Error = cfgrammar::header::HeaderError; - fn try_from(kind: SerialisationFormat) -> Result, HeaderError> { + fn try_from( + kind: SerialisationFormat, + ) -> Result, HeaderError> { 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), - })), - SerialisationFormat::VariableSizedInteger => { - Value::Setting(Setting::Unitary(Namespaced { - namespace: Some(("serialisationformat".to_string(), from_loc.clone())), - member: ("variablesizedinteger".to_string(), from_loc), - })) - } - }) + Ok(GrmtoolsSectionValue::RustLike( + format!("SerialisationFormat::{kind:?}"), + from_loc, + )) } } -impl TryFrom<&Value> for SerialisationFormat { +impl TryFrom<&GrmtoolsSectionValue> for SerialisationFormat { type Error = HeaderError; - fn try_from(value: &Value) -> Result> { - let mut err_locs = Vec::new(); + fn try_from(value: &GrmtoolsSectionValue) -> Result> { match value { - // Finally handle enum values. - Value::Setting(Setting::Unitary(Namespaced { - namespace, - member: (enc_value, enc_value_loc), - })) => { - if let Some((ns, ns_loc)) = namespace - && ns != "serialisationformat" - { - err_locs.push(ns_loc.clone()); - } - let encodings = [ - ( - "fixedsizeinteger".to_string(), - SerialisationFormat::FixedSizeInteger, - ), - ( - "variablesizedinteger".to_string(), - SerialisationFormat::VariableSizedInteger, - ), - ]; - let enc_found = encodings - .iter() - .find_map(|(enc_str, enc)| (enc_str == enc_value).then_some(enc)); - if let Some(enc) = enc_found { - if err_locs.is_empty() { - Ok(*enc) - } else { - Err(HeaderError { - kind: HeaderErrorKind::InvalidEntry("serialisation_format"), - locations: err_locs, - }) + GrmtoolsSectionValue::RustLike(serialisation_fmt, loc) => { + match serialisation_fmt.as_str() { + "SerialisationFormat::FixedSizeInteger" | "FixedSizeInteger" => { + Ok(SerialisationFormat::FixedSizeInteger) } - } else { - err_locs.push(enc_value_loc.clone()); - Err(HeaderError { + "SerialisationFormat::VariableSizedInteger" | "VariableSizedInteger" => { + Ok(SerialisationFormat::VariableSizedInteger) + } + _ => Err(HeaderError { kind: HeaderErrorKind::InvalidEntry("serialisation_format"), - locations: err_locs, - }) + locations: vec![loc.clone()], + }), } } - val => { - err_locs.push(val.primary_location().clone()); - Err(HeaderError { - kind: HeaderErrorKind::InvalidEntry("serialisation_format"), - locations: err_locs, - }) - } + val => Err(HeaderError { + kind: HeaderErrorKind::InvalidEntry("serialisation_format"), + locations: vec![val.primary_location().clone()], + }), } } } @@ -561,7 +525,7 @@ where Entry::Vacant(mut v) => match self.yacckind { Some(YaccKind::Eco) => panic!("Eco compile-time grammar generation not supported."), Some(yk) => { - let yk_value = Value::try_from(yk)?; + let yk_value = GrmtoolsSectionValue::try_from(yk)?; let mut o = v.insert_entry(HeaderValue( Location::Other("CTParserBuilder".to_string()), yk_value, @@ -577,7 +541,7 @@ where match header.entry("lrpar.recoverer".to_string()) { Entry::Occupied(_) => unreachable!(), Entry::Vacant(v) => { - let rk_value: Value = Value::try_from(recoverer)?; + let rk_value = GrmtoolsSectionValue::try_from(recoverer)?; let mut o = v.insert_entry(HeaderValue( Location::Other("CTParserBuilder".to_string()), rk_value, @@ -591,7 +555,7 @@ where match header.entry("lrpar.serialisation_format".to_string()) { Entry::Occupied(_) => unreachable!(), Entry::Vacant(v) => { - let rk_value: Value = Value::try_from(encoding)?; + let rk_value = GrmtoolsSectionValue::try_from(encoding)?; let mut o = v.insert_entry(HeaderValue( Location::Other("CTParserBuilder".to_string()), rk_value, diff --git a/lrpar/src/lib/parser.rs b/lrpar/src/lib/parser.rs index 959021343..a838abd13 100644 --- a/lrpar/src/lib/parser.rs +++ b/lrpar/src/lib/parser.rs @@ -14,7 +14,12 @@ use std::time::{Duration, Instant}; use web_time::{Duration, Instant}; use cactus::Cactus; -use cfgrammar::{RIdx, Span, TIdx, header::Value, span::Location, yacc::YaccGrammar}; +use cfgrammar::{ + RIdx, Span, TIdx, + header::{GrmtoolsSectionValue, HeaderError, HeaderErrorKind}, + span::Location, + yacc::YaccGrammar, +}; use lrtable::{Action, StIdx, StateTable}; use num_traits::{AsPrimitive, PrimInt, Unsigned}; use proc_macro2::TokenStream; @@ -635,58 +640,32 @@ pub enum RecoveryKind { None, } -impl TryFrom for Value { +impl TryFrom for GrmtoolsSectionValue { type Error = cfgrammar::header::HeaderError; - fn try_from(rk: RecoveryKind) -> Result, Self::Error> { - use cfgrammar::{ - Location, - header::{Namespaced, Setting}, - }; + fn try_from(rk: RecoveryKind) -> Result, Self::Error> { let from_loc = Location::Other("From".to_string()); - Ok(match rk { - RecoveryKind::CPCTPlus => Value::Setting(Setting::Unitary(Namespaced { - namespace: Some(("RecoveryKind".to_string(), from_loc.clone())), - member: ("CPCTPlus".to_string(), from_loc.clone()), - })), - RecoveryKind::None => Value::Setting(Setting::Unitary(Namespaced { - namespace: Some(("RecoveryKind".to_string(), from_loc.clone())), - member: ("None".to_string(), from_loc.clone()), - })), - }) + Ok(GrmtoolsSectionValue::RustLike( + format!("RecoveryKind::{rk:?}"), + from_loc, + )) } } -impl TryFrom<&Value> for RecoveryKind { +impl TryFrom<&GrmtoolsSectionValue> for RecoveryKind { type Error = cfgrammar::header::HeaderError; - fn try_from(rk: &Value) -> Result { - use cfgrammar::header::{HeaderError, HeaderErrorKind, Namespaced, Setting}; - + fn try_from(rk: &GrmtoolsSectionValue) -> Result { match rk { - Value::Setting(Setting::Unitary(Namespaced { - namespace, - member: (kind, kind_loc), - })) => { - match namespace { - Some((ns, loc)) if ns.to_lowercase() != "recoverykind" => { - return Err(HeaderError { - kind: HeaderErrorKind::ConversionError( - "RecoveryKind", - "Unknown namespace", - ), - locations: vec![loc.clone()], - }); - } - _ => {} - } - match kind.to_lowercase().as_ref() { - "cpctplus" => Ok(RecoveryKind::CPCTPlus), - "none" => Ok(RecoveryKind::None), - _ => Err(HeaderError { - kind: HeaderErrorKind::ConversionError("RecoveryKind", "Unknown variant"), - locations: vec![kind_loc.clone()], - }), - } - } + GrmtoolsSectionValue::RustLike(rs, loc) => match rs.as_str() { + "RecoveryKind::CPCTPlus" | "CPCTPlus" => Ok(RecoveryKind::CPCTPlus), + "RecoveryKind::None" | "None" => Ok(RecoveryKind::None), + _ => Err(HeaderError { + kind: HeaderErrorKind::ConversionError( + "RecoveryKind", + "Cannot convert to RecoveryKind", + ), + locations: vec![loc.clone()], + }), + }, value => Err(HeaderError { kind: HeaderErrorKind::ConversionError( "RecoveryKind", @@ -1367,7 +1346,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..4c2a7d297 100644 --- a/nimbleparse/src/main.rs +++ b/nimbleparse/src/main.rs @@ -1,6 +1,6 @@ use cfgrammar::{ Location, RIdx, Span, TIdx, - header::{GrmtoolsSectionParser, Header, HeaderError, HeaderValue, Setting, Value}, + header::{GrmtoolsSectionParser, GrmtoolsSectionValue, Header, HeaderError, HeaderValue}, markmap::Entry, yacc::{YaccGrammar, YaccKind, YaccOriginalActionKind, ast::ASTWithValidityInfo}, }; @@ -185,7 +185,7 @@ fn main() { "lrpar.recoverer".to_string(), HeaderValue( Location::CommandLine, - Value::try_from(match &*s.to_lowercase() { + GrmtoolsSectionValue::try_from(match &*s.to_lowercase() { "cpctplus" => RecoveryKind::CPCTPlus, "none" => RecoveryKind::None, _ => usage(prog, &format!("Unknown recoverer '{}'.", s)), @@ -204,7 +204,7 @@ fn main() { Some(s) => { entry.insert_entry(HeaderValue( Location::CommandLine, - Value::try_from(match &*s.to_lowercase() { + GrmtoolsSectionValue::try_from(match &*s.to_lowercase() { "eco" => YaccKind::Eco, "grmtools" => YaccKind::Grmtools, "original" => YaccKind::Original(YaccOriginalActionKind::GenericParseTree), @@ -552,10 +552,10 @@ where } else { // If given no input paths, try to find some with `test_files` in the header. match self.header.get("lrpar.test_files") { - Some(HeaderValue(_, Value::Setting(Setting::Array(test_globs, _, _)))) => { + Some(HeaderValue(_, GrmtoolsSectionValue::Array(test_globs, _))) => { for setting in test_globs { match setting { - Setting::String(s, _) => { + GrmtoolsSectionValue::String(s, _) => { if let Some(yacc_y_path_dir) = self.yacc_y_path.parent() { let joined = yacc_y_path_dir.join(s); let joined = joined.as_os_str().to_str();