Skip to content

Commit fcaefc9

Browse files
committed
Add tests for header value recoverykind
1 parent fad02ac commit fcaefc9

3 files changed

Lines changed: 103 additions & 150 deletions

File tree

lrlex/src/lib/ctbuilder.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,18 +344,17 @@ where
344344
/// module name is `c_l` (i.e. the file's leaf name, minus its extension, with a prefix of
345345
/// `_l`).
346346
pub fn build(mut self) -> Result<CTLexer, Box<dyn Error>> {
347-
let lexerp = self
348-
.lexer_path
349-
.as_ref()
350-
.expect("lexer_path must be specified before processing.");
351347
if let Some(ref lrcfg) = self.lrpar_config {
352348
let mut ctp = CTParserBuilder::<LexerTypesT>::new();
353-
ctp = ctp.lexer_path(lexerp.to_owned());
354349
ctp = lrcfg(ctp);
355350
let map = ctp.build()?;
356351
self.rule_ids_map = Some(map.token_map().to_owned());
357352
}
358353

354+
let lexerp = self
355+
.lexer_path
356+
.as_ref()
357+
.expect("lexer_path must be specified before processing.");
359358
let outp = self
360359
.output_path
361360
.as_ref()

lrpar/cttests/build.rs

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -47,87 +47,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
4747
.unwrap();
4848
}
4949

50-
{
51-
use lrpar::RecoveryKind as RK;
52-
#[rustfmt::skip]
53-
let recovery_kinds = [
54-
// Builder, Header setting, Expected result.
55-
// ----------- ------------------ -------------------
56-
(Some(RK::None), Some(RK::None), Some(RK::None)),
57-
(Some(RK::None), Some(RK::CPCTPlus), Some(RK::None)),
58-
(Some(RK::CPCTPlus), Some(RK::CPCTPlus), Some(RK::CPCTPlus)),
59-
(Some(RK::CPCTPlus), Some(RK::None), Some(RK::CPCTPlus)),
60-
(None, Some(RK::CPCTPlus), Some(RK::CPCTPlus)),
61-
(None, Some(RK::None), Some(RK::None)),
62-
(None, None, Some(RK::CPCTPlus)),
63-
(Some(RK::None), None, Some(RK::None)),
64-
(Some(RK::CPCTPlus), None, Some(RK::CPCTPlus)),
65-
];
66-
67-
for (i, (builder_arg, header_arg, expected_rk)) in
68-
recovery_kinds.iter().cloned().enumerate()
69-
{
70-
let y_src = if let Some(header_arg) = header_arg {
71-
format!(
72-
"\
73-
%grmtools{{yacckind: Original(NoAction), recoverer: {}}} \
74-
%% \
75-
start: ; \
76-
",
77-
match header_arg {
78-
RK::None => "RecoveryKind::None",
79-
RK::CPCTPlus => "RecoveryKind::CPCTPlus",
80-
_ => panic!("Unrecognized recoverykind"),
81-
}
82-
)
83-
} else {
84-
r#"
85-
%grmtools{yacckind: Original(NoAction)}
86-
%%
87-
Start: ;
88-
"#
89-
.to_string()
90-
};
91-
let out_dir = std::env::var("OUT_DIR").unwrap();
92-
let y_path = format!("{out_dir}/recoverykind_test_{i}.y");
93-
let y_out_path = format!("{y_path}.rs");
94-
let l_src = r#"
95-
%%
96-
. ;"#;
97-
let l_path = format!("{out_dir}/recoverykind_tests.l");
98-
let l_out_path = format!("{out_dir}/recoverykind_tests_{i}.l.rs");
99-
std::fs::File::create(l_path.clone()).unwrap();
100-
std::fs::write(l_path.clone(), l_src).unwrap();
101-
eprintln!("{:?} {:?}", y_path, l_path);
102-
std::fs::File::create(y_path.clone()).unwrap();
103-
std::fs::write(y_path.clone(), y_src).unwrap();
104-
let mut cl_builder = CTLexerBuilder::new()
105-
.output_path(l_out_path)
106-
.lexer_path(l_path);
107-
cl_builder = cl_builder.lrpar_config(move |mut cp_builder| {
108-
cp_builder = cp_builder
109-
.output_path(y_out_path.clone())
110-
.grammar_path(y_path.clone());
111-
if let Some(builder_arg) = builder_arg {
112-
cp_builder.recoverer(builder_arg)
113-
} else {
114-
cp_builder
115-
}
116-
.inspect(Box::new(move |_, rk, _, _, _, _| {
117-
if matches!(
118-
(rk, expected_rk),
119-
(RK::None, Some(RK::None)) | (RK::CPCTPlus, Some(RK::CPCTPlus))
120-
) {
121-
Ok(())
122-
} else {
123-
panic!("Unexpected recovery kind")
124-
}
125-
}))
126-
});
127-
128-
cl_builder.build()?;
129-
}
130-
}
13150
println!("cargo::rerun-if-changed=src/storaget.l");
13251
println!(
13352
"cargo::rerun-if-changed={}/storaget.l.rs",

lrpar/src/lib/ctbuilder.rs

Lines changed: 99 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -242,20 +242,9 @@ where
242242
show_warnings: bool,
243243
visibility: Visibility,
244244
rust_edition: RustEdition,
245-
lexer_path: Option<PathBuf>,
246-
// We want lifetimes that imply the callback can't capture the header or the grammar.
247-
inspect_callback: Option<
248-
Box<
249-
dyn for<'y> Fn(
250-
&'y mut Header,
251-
RecoveryKind,
252-
&'y YaccGrammar<LexerTypesT::StorageT>,
253-
&'y StateTable<LexerTypesT::StorageT>,
254-
&'y StateGraph<LexerTypesT::StorageT>,
255-
Option<PathBuf>,
256-
) -> Result<(), Box<dyn Error>>,
257-
>,
258-
>,
245+
// test function for inspecting private state
246+
#[cfg(test)]
247+
inspect_callback: Option<Box<dyn Fn(RecoveryKind) -> Result<(), Box<dyn Error>>>>,
259248
phantom: PhantomData<LexerTypesT>,
260249
}
261250

@@ -300,8 +289,8 @@ where
300289
show_warnings: true,
301290
visibility: Visibility::Private,
302291
rust_edition: RustEdition::Rust2021,
292+
#[cfg(test)]
303293
inspect_callback: None,
304-
lexer_path: None,
305294
phantom: PhantomData,
306295
}
307296
}
@@ -432,25 +421,10 @@ where
432421
self
433422
}
434423

435-
/// Sets the path to the lexer sources this is for usage from within callbacks only, and
436-
/// not used during the build process.
437-
pub fn lexer_path(mut self, lexer_path: PathBuf) -> Self {
438-
self.lexer_path = Some(lexer_path);
439-
self
440-
}
441-
442-
pub fn inspect(
424+
#[cfg(test)]
425+
pub fn inspect_recoverer(
443426
mut self,
444-
cb: Box<
445-
dyn for<'h, 'y> Fn(
446-
&'h mut Header,
447-
RecoveryKind,
448-
&'y YaccGrammar<StorageT>,
449-
&'y StateTable<StorageT>,
450-
&'y StateGraph<StorageT>,
451-
Option<PathBuf>,
452-
) -> Result<(), Box<dyn Error>>,
453-
>,
427+
cb: Box<dyn for<'h, 'y> Fn(RecoveryKind) -> Result<(), Box<dyn Error>>>,
454428
) -> Self {
455429
self.inspect_callback = Some(cb);
456430
self
@@ -652,6 +626,24 @@ where
652626
}
653627
};
654628

629+
#[cfg(test)]
630+
if let Some(cb) = &self.inspect_callback {
631+
cb(self.recoverer.expect("has a default value"))?;
632+
}
633+
634+
let unused_keys = header.unused();
635+
if !unused_keys.is_empty() {
636+
return Err(format!("Unused keys in header: {}", unused_keys.join(", ")).into());
637+
}
638+
let missing_keys = header.missing();
639+
if !missing_keys.is_empty() {
640+
return Err(format!(
641+
"Required values were missing from the header: {}",
642+
unused_keys.join(", ")
643+
)
644+
.into());
645+
}
646+
655647
let rule_ids = grm
656648
.tokens_map()
657649
.iter()
@@ -721,31 +713,6 @@ where
721713
fs::remove_file(outp).ok();
722714

723715
let (sgraph, stable) = from_yacc(&grm, Minimiser::Pager)?;
724-
725-
if let Some(cb) = &self.inspect_callback {
726-
cb(
727-
&mut header,
728-
self.recoverer.expect("has a default value"),
729-
&grm,
730-
&stable,
731-
&sgraph,
732-
self.lexer_path.clone(),
733-
)?;
734-
}
735-
736-
let unused_keys = header.unused();
737-
if !unused_keys.is_empty() {
738-
return Err(format!("Unused keys in header: {}", unused_keys.join(", ")).into());
739-
}
740-
let missing_keys = header.missing();
741-
if !missing_keys.is_empty() {
742-
return Err(format!(
743-
"Required values were missing from the header: {}",
744-
unused_keys.join(", ")
745-
)
746-
.into());
747-
}
748-
749716
if self.error_on_conflicts {
750717
if let Some(c) = stable.conflicts() {
751718
match (grm.expect(), grm.expectrr()) {
@@ -872,8 +839,8 @@ where
872839
show_warnings: self.show_warnings,
873840
visibility: self.visibility.clone(),
874841
rust_edition: self.rust_edition,
842+
#[cfg(test)]
875843
inspect_callback: None,
876-
lexer_path: self.lexer_path.clone(),
877844
phantom: PhantomData,
878845
};
879846
Ok(cl.build()?.rule_ids)
@@ -962,14 +929,12 @@ where
962929
show_warnings,
963930
visibility,
964931
rust_edition,
965-
inspect_callback: _,
966-
lexer_path,
932+
#[cfg(test)]
933+
inspect_callback: _,
967934
phantom: _,
968935
} = self;
969936
let build_time = env!("VERGEN_BUILD_TIMESTAMP");
970937
let grammar_path = grammar_path.as_ref().unwrap().to_string_lossy();
971-
let empty_path = PathBuf::new();
972-
let lexer_path = lexer_path.as_ref().unwrap_or(&empty_path).to_string_lossy();
973938
let mod_name = QuoteOption(mod_name.as_deref());
974939
let visibility = visibility.to_variant_tokens();
975940
let rust_edition = rust_edition.to_variant_tokens();
@@ -996,7 +961,6 @@ where
996961
RUST_EDITION = #rust_edition
997962
RULE_IDS_MAP = [#(#rule_map,)*]
998963
VISIBILITY = #visibility
999-
LEX_PATH = #lexer_path
1000964
};
1001965
let cache_info_str = cache_info.to_string();
1002966
quote!(#cache_info_str)
@@ -1655,4 +1619,75 @@ C : 'a';"
16551619
}
16561620
}
16571621
}
1622+
1623+
#[cfg(test)]
1624+
#[test]
1625+
fn test_recoverer_header() -> Result<(), Box<dyn std::error::Error>> {
1626+
use crate::RecoveryKind as RK;
1627+
#[rustfmt::skip]
1628+
let recovery_kinds = [
1629+
// Builder, Header setting, Expected result.
1630+
// ----------- ------------------ -------------------
1631+
(Some(RK::None), Some(RK::None), Some(RK::None)),
1632+
(Some(RK::None), Some(RK::CPCTPlus), Some(RK::None)),
1633+
(Some(RK::CPCTPlus), Some(RK::CPCTPlus), Some(RK::CPCTPlus)),
1634+
(Some(RK::CPCTPlus), Some(RK::None), Some(RK::CPCTPlus)),
1635+
(None, Some(RK::CPCTPlus), Some(RK::CPCTPlus)),
1636+
(None, Some(RK::None), Some(RK::None)),
1637+
(None, None, Some(RK::CPCTPlus)),
1638+
(Some(RK::None), None, Some(RK::None)),
1639+
(Some(RK::CPCTPlus), None, Some(RK::CPCTPlus)),
1640+
];
1641+
1642+
for (i, (builder_arg, header_arg, expected_rk)) in
1643+
recovery_kinds.iter().cloned().enumerate()
1644+
{
1645+
let y_src = if let Some(header_arg) = header_arg {
1646+
format!(
1647+
"\
1648+
%grmtools{{yacckind: Original(NoAction), recoverer: {}}} \
1649+
%% \
1650+
start: ; \
1651+
",
1652+
match header_arg {
1653+
RK::None => "RecoveryKind::None",
1654+
RK::CPCTPlus => "RecoveryKind::CPCTPlus",
1655+
}
1656+
)
1657+
} else {
1658+
r#"
1659+
%grmtools{yacckind: Original(NoAction)}
1660+
%%
1661+
Start: ;
1662+
"#
1663+
.to_string()
1664+
};
1665+
let out_dir = std::env::var("OUT_DIR").unwrap();
1666+
let y_path = format!("{out_dir}/recoverykind_test_{i}.y");
1667+
let y_out_path = format!("{y_path}.rs");
1668+
std::fs::File::create(y_path.clone()).unwrap();
1669+
std::fs::write(y_path.clone(), y_src).unwrap();
1670+
let mut cp_builder = CTParserBuilder::<TestLexerTypes>::new();
1671+
cp_builder = cp_builder
1672+
.output_path(y_out_path.clone())
1673+
.grammar_path(y_path.clone());
1674+
cp_builder = if let Some(builder_arg) = builder_arg {
1675+
cp_builder.recoverer(builder_arg)
1676+
} else {
1677+
cp_builder
1678+
}
1679+
.inspect_recoverer(Box::new(move |rk| {
1680+
if matches!(
1681+
(rk, expected_rk),
1682+
(RK::None, Some(RK::None)) | (RK::CPCTPlus, Some(RK::CPCTPlus))
1683+
) {
1684+
Ok(())
1685+
} else {
1686+
panic!("Unexpected recovery kind")
1687+
}
1688+
}));
1689+
cp_builder.build()?;
1690+
}
1691+
Ok(())
1692+
}
16581693
}

0 commit comments

Comments
 (0)