Skip to content

Commit 7f83351

Browse files
committed
fix: Recursive parsing of attributes
The `test_parse` macro is changed to recursively parse attributes, filtering out the `#[ignore]` macro. This should also make it fairly trivial to add additional macros, such as `#[should_ignore]`. There is a fair amount of complexity added to the macro with this change, but on the other hand, it also succeeds in generating only the necessary code. You win some, you lose some.
1 parent e08a5b9 commit 7f83351

File tree

1 file changed

+60
-18
lines changed

1 file changed

+60
-18
lines changed

crates/libtest2/src/macros.rs

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,58 @@ macro_rules! _main_parse {
1414
}
1515

1616
#[macro_export]
17-
macro_rules! _parse_ignore {
18-
(ignore) => {
19-
::std::option::Option::<&'static str>::None
17+
#[allow(clippy::crate_in_macro_def)] // accessing item defined by `_main_parse`/`_parse_ignore`, and recursively calling the macro itself
18+
macro_rules! _test_parse {
19+
// Entry point
20+
(#[test] $(#[$($attr:tt)+])* fn $name:ident $($item:tt)*) => {
21+
$crate::_private::test_parse!(continue:
22+
name=$name
23+
body=[$($item)*]
24+
attrs=[$(#[$($attr)+])*]
25+
);
26+
};
27+
28+
// Recursively handle attributes:
29+
30+
// Edge condition (no more attributes to parse)
31+
(continue: name=$name:ident body=[$($item:tt)*] attrs=[] $(ignore=$ignore:tt)?) => {
32+
$crate::_private::test_parse!(break:
33+
name=$name
34+
body=[$($item)*]
35+
$(ignore=$ignore)?
36+
);
2037
};
21-
(ignore = $reason:expr) => {
22-
::std::option::Option::<&'static str>::Some($reason)
38+
// Process `#[ignore]`/`#[ignore = ".."]` (NOTE: This will only match if an ignore macro has not already been parsed)
39+
(continue: name=$name:ident body=[$($item:tt)*] attrs=[#[ignore $(= $reason:literal)?] $(#[$($attr:tt)+])*]) => {
40+
$crate::_private::test_parse!(continue:
41+
name=$name
42+
body=[$($item)*]
43+
attrs=[$(#[$($attr)*])*]
44+
ignore=[$($reason)?]
45+
);
2346
};
24-
($($attr:tt)*) => {
25-
compile_error!(concat!("unknown attribute '", stringify!($($attr)*), "'"));
47+
// Ignore subsequent calls to `#[ignore]`/`#[ignore = ".."]`
48+
(continue: name=$name:ident body=[$($item:tt)*] attrs=[#[ignore $(= $reason:literal)?] $(#[$($attr:tt)+])*] ignore=$ignore:tt) => {
49+
$crate::_private::test_parse!(continue:
50+
name=$name
51+
body=[$($item)*]
52+
attrs=[$(#[$($attr)*])*]
53+
ignore=$ignore
54+
);
55+
};
56+
// Emit error on unknown attributes (but continue parsing)
57+
(continue: name=$name:ident body=[$($item:tt)*] attrs=[#[$($unknown_attr:tt)+] $(#[$($attr:tt)+])*] $(ignore=$ignore:tt)?) => {
58+
compile_error!(concat!("unknown attribute '", stringify!($($unknown_attr)+), "'"));
59+
$crate::_private::test_parse!(continue:
60+
name=$name
61+
body=[$($item)*]
62+
attrs=[$(#[$($attr)*])*]
63+
$(ignore=$ignore)?
64+
);
2665
};
27-
}
2866

29-
#[macro_export]
30-
#[allow(clippy::crate_in_macro_def)] // accessing item defined by `_main_parse`
31-
macro_rules! _test_parse {
32-
(#[test] $(#[$($attr:tt)*])* fn $name:ident $($item:tt)*) => {
67+
// End result
68+
(break: name=$name:ident body=[$($item:tt)*] $(ignore=$ignore:tt)?) => {
3369
#[allow(non_camel_case_types)]
3470
struct $name;
3571

@@ -52,12 +88,7 @@ macro_rules! _test_parse {
5288
fn run(&self, context: &$crate::TestContext) -> $crate::RunResult {
5389
fn run $($item)*
5490

55-
$(
56-
match $crate::_private::parse_ignore!($($attr)*) {
57-
::std::option::Option::None => context.ignore()?,
58-
::std::option::Option::Some(reason) => context.ignore_for(reason)?,
59-
}
60-
)*
91+
$crate::_private::parse_ignore!(context, $($ignore)?);
6192

6293
use $crate::IntoRunResult;
6394
let result = run(context);
@@ -66,3 +97,14 @@ macro_rules! _test_parse {
6697
}
6798
};
6899
}
100+
101+
#[macro_export]
102+
macro_rules! _parse_ignore {
103+
($context:expr, [$reason:literal] $(,)?) => {
104+
$context.ignore_for($reason)?
105+
};
106+
($context:expr, [] $(,)?) => {
107+
$context.ignore()?
108+
};
109+
($context:expr $(,)?) => {};
110+
}

0 commit comments

Comments
 (0)