Skip to content

Commit

Permalink
Implement ${count()} metavariable expression
Browse files Browse the repository at this point in the history
  • Loading branch information
lowr committed May 28, 2023
1 parent 9ebaa85 commit 0d4d1d7
Show file tree
Hide file tree
Showing 7 changed files with 389 additions and 29 deletions.
220 changes: 220 additions & 0 deletions crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,223 @@ const _: i32 = -0--1--2;
"#]],
);
}

#[test]
fn count_basic() {
check(
r#"
macro_rules! m {
($($t:ident),*) => {
${count(t)}
}
}
fn test() {
m!();
m!(a);
m!(a, a);
}
"#,
expect![[r#"
macro_rules! m {
($($t:ident),*) => {
${count(t)}
}
}
fn test() {
0;
1;
2;
}
"#]],
);
}

#[test]
fn count_with_depth() {
check(
r#"
macro_rules! foo {
($( $( $($t:ident)* ),* );*) => {
$(
{
let depth_none = ${count(t)};
let depth_zero = ${count(t, 0)};
let depth_one = ${count(t, 1)};
}
)*
}
}
fn bar() {
foo!(
a a a, a, a a;
a a a
)
}
"#,
expect![[r#"
macro_rules! foo {
($( $( $($t:ident)* ),* );*) => {
$(
{
let depth_none = ${count(t)};
let depth_zero = ${count(t, 0)};
let depth_one = ${count(t, 1)};
}
)*
}
}
fn bar() {
{
let depth_none = 6;
let depth_zero = 3;
let depth_one = 6;
} {
let depth_none = 3;
let depth_zero = 1;
let depth_one = 3;
}
}
"#]],
);
}

#[test]
fn count_depth_out_of_bounds() {
check(
r#"
macro_rules! foo {
($($t:ident)*) => { ${count(t, 1)} };
($( $( $l:literal )* );*) => { $(${count(l, 1)};)* }
}
macro_rules! bar {
($($t:ident)*) => { ${count(t, 1024)} };
($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* }
}
fn test() {
foo!(a b);
foo!(1 2; 3);
bar!(a b);
bar!(1 2; 3);
}
"#,
expect![[r#"
macro_rules! foo {
($($t:ident)*) => { ${count(t, 1)} };
($( $( $l:literal )* );*) => { $(${count(l, 1)};)* }
}
macro_rules! bar {
($($t:ident)*) => { ${count(t, 1024)} };
($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* }
}
fn test() {
/* error: ${count} out of bounds */;
/* error: ${count} out of bounds */;
/* error: ${count} out of bounds */;
/* error: ${count} out of bounds */;
}
"#]],
);
}

#[test]
fn misplaced_count() {
check(
r#"
macro_rules! foo {
($($t:ident)*) => { $(${count(t)})* };
($l:literal) => { ${count(l)} }
}
fn test() {
foo!(a b c);
foo!(1);
}
"#,
expect![[r#"
macro_rules! foo {
($($t:ident)*) => { $(${count(t)})* };
($l:literal) => { ${count(l)} }
}
fn test() {
/* error: ${count} misplaced */;
/* error: ${count} misplaced */;
}
"#]],
);
}

#[test]
fn malformed_count() {
check(
r#"
macro_rules! too_many_args {
($($t:ident)*) => { ${count(t, 1, leftover)} }
}
macro_rules! depth_suffixed {
($($t:ident)*) => { ${count(t, 0usize)} }
}
macro_rules! depth_too_large {
($($t:ident)*) => { ${count(t, 18446744073709551616)} }
}
fn test() {
too_many_args!();
depth_suffixed!();
depth_too_large!();
}
"#,
expect![[r#"
macro_rules! too_many_args {
($($t:ident)*) => { ${count(t, 1, leftover)} }
}
macro_rules! depth_suffixed {
($($t:ident)*) => { ${count(t, 0usize)} }
}
macro_rules! depth_too_large {
($($t:ident)*) => { ${count(t, 18446744073709551616)} }
}
fn test() {
/* error: invalid macro definition: invalid metavariable expression */;
/* error: invalid macro definition: invalid metavariable expression */;
/* error: invalid macro definition: invalid metavariable expression */;
}
"#]],
);
}

#[test]
fn count_interaction_with_empty_binding() {
// FIXME: Should this error? rustc currently accepts it.
check(
r#"
macro_rules! m {
($($t:ident),*) => {
${count(t, 100)}
}
}
fn test() {
m!();
}
"#,
expect![[r#"
macro_rules! m {
($($t:ident),*) => {
${count(t, 100)}
}
}
fn test() {
0;
}
"#]],
);
}
2 changes: 1 addition & 1 deletion crates/mbe/src/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(Stri
});
parent.token_trees.push(subtree.into());
}
Op::Ignore { .. } | Op::Index { .. } => {}
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } => {}
};

// Simple linear congruential generator for deterministic result
Expand Down
8 changes: 6 additions & 2 deletions crates/mbe/src/expander/matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,9 @@ fn match_loop_inner<'t>(
item.is_error = true;
error_items.push(item);
}
OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. }) => {}
OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. }) => {
stdx::never!("metavariable expression in lhs found");
}
OpDelimited::Open => {
if matches!(src.peek_n(0), Some(tt::TokenTree::Subtree(..))) {
item.dot.next();
Expand Down Expand Up @@ -811,7 +813,9 @@ fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate)
Op::Var { name, .. } => collector_fun(name.clone()),
Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens),
Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens),
Op::Ignore { .. } | Op::Index { .. } | Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => {
Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => {}
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } => {
stdx::never!("metavariable expression in lhs found");
}
}
}
Expand Down
Loading

0 comments on commit 0d4d1d7

Please sign in to comment.