Merge #10496
10496: internal: move some macro tests r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
b2b703b2d7
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -345,9 +345,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "expect-test"
|
||||
version = "1.1.0"
|
||||
version = "1.2.0-pre.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2300477aab3a378f2ca00a4fbd4dc713654ab7ed790e4017493cb33656280633"
|
||||
checksum = "3a2f1664bc69648747878bfe3430ad9b58bc8d9b50b3b1df9f3c081345e33197"
|
||||
dependencies = [
|
||||
"dissimilar",
|
||||
"once_cell",
|
||||
|
@ -16,7 +16,7 @@ tt = { path = "../tt", version = "0.0.0" }
|
||||
[dev-dependencies]
|
||||
mbe = { path = "../mbe" }
|
||||
syntax = { path = "../syntax" }
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
oorandom = "11"
|
||||
# We depend on both individually instead of using `features = ["derive"]` to microoptimize the
|
||||
# build graph: if the feature was enabled, syn would be built early on in the graph if `smolstr`
|
||||
|
@ -35,4 +35,4 @@ limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
@ -28,7 +28,7 @@ use crate::{
|
||||
db::DefDatabase, nameres::ModuleSource, resolver::HasResolver, test_db::TestDB, AsMacroCall,
|
||||
};
|
||||
|
||||
fn check(ra_fixture: &str, expect: Expect) {
|
||||
fn check(ra_fixture: &str, mut expect: Expect) {
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
let krate = db.crate_graph().iter().next().unwrap();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
@ -65,16 +65,29 @@ fn check(ra_fixture: &str, expect: Expect) {
|
||||
format_to!(expn_text, "/* error: {} */", err);
|
||||
}
|
||||
if let Some((parse, _token_map)) = exp.value {
|
||||
assert!(
|
||||
parse.errors().is_empty(),
|
||||
"parse errors in expansion: \n{:#?}",
|
||||
parse.errors()
|
||||
);
|
||||
let pp = pretty_print_macro_expansion(parse.syntax_node());
|
||||
let indent = IndentLevel::from_node(call.syntax());
|
||||
let pp = reindent(indent, pp);
|
||||
format_to!(expn_text, "{}", pp);
|
||||
if call.to_string().contains("// +tree") {
|
||||
let tree = format!("{:#?}", parse.syntax_node())
|
||||
.split_inclusive("\n")
|
||||
.map(|line| format!("// {}", line))
|
||||
.collect::<String>();
|
||||
format_to!(expn_text, "\n{}", tree)
|
||||
}
|
||||
}
|
||||
let range = call.syntax().text_range();
|
||||
let range: Range<usize> = range.into();
|
||||
expanded_text.replace_range(range, &expn_text)
|
||||
}
|
||||
|
||||
expect.indent(false);
|
||||
expect.assert_eq(&expanded_text);
|
||||
}
|
||||
|
||||
@ -97,20 +110,37 @@ fn reindent(indent: IndentLevel, pp: String) -> String {
|
||||
fn pretty_print_macro_expansion(expn: SyntaxNode) -> String {
|
||||
let mut res = String::new();
|
||||
let mut prev_kind = SyntaxKind::EOF;
|
||||
let mut indent_level = 0;
|
||||
for token in iter::successors(expn.first_token(), |t| t.next_token()) {
|
||||
let curr_kind = token.kind();
|
||||
let space = match (prev_kind, curr_kind) {
|
||||
_ if prev_kind.is_trivia() || curr_kind.is_trivia() => "",
|
||||
(T!['{'], T!['}']) => "",
|
||||
(T![=], _) | (_, T![=]) => " ",
|
||||
(_, T!['{']) => " ",
|
||||
(T![;] | T!['}'], _) => "\n",
|
||||
(T![;] | T!['{'] | T!['}'], _) => "\n",
|
||||
(_, T!['}']) => "\n",
|
||||
(IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ",
|
||||
(IDENT, _) if curr_kind.is_keyword() => " ",
|
||||
(_, IDENT) if prev_kind.is_keyword() => " ",
|
||||
(T![>], IDENT) => " ",
|
||||
(T![>], _) if curr_kind.is_keyword() => " ",
|
||||
(T![->], _) | (_, T![->]) => " ",
|
||||
(T![&&], _) | (_, T![&&]) => " ",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
match prev_kind {
|
||||
T!['{'] => indent_level += 1,
|
||||
T!['}'] => indent_level -= 1,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
res.push_str(space);
|
||||
if space == "\n" {
|
||||
let level = if curr_kind == T!['}'] { indent_level - 1 } else { indent_level };
|
||||
res.push_str(&" ".repeat(level));
|
||||
}
|
||||
prev_kind = curr_kind;
|
||||
format_to!(res, "{}", token)
|
||||
}
|
||||
|
@ -9,6 +9,45 @@ use expect_test::expect;
|
||||
|
||||
use crate::macro_expansion_tests::check;
|
||||
|
||||
#[test]
|
||||
fn mbe_smoke_test() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! impl_froms {
|
||||
($e:ident: $($v:ident),*) => {
|
||||
$(
|
||||
impl From<$v> for $e {
|
||||
fn from(it: $v) -> $e { $e::$v(it) }
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
impl_froms!(TokenTree: Leaf, Subtree);
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! impl_froms {
|
||||
($e:ident: $($v:ident),*) => {
|
||||
$(
|
||||
impl From<$v> for $e {
|
||||
fn from(it: $v) -> $e { $e::$v(it) }
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
impl From<Leaf> for TokenTree {
|
||||
fn from(it:Leaf) -> TokenTree {
|
||||
TokenTree::Leaf(it)
|
||||
}
|
||||
}
|
||||
impl From<Subtree> for TokenTree {
|
||||
fn from(it:Subtree) -> TokenTree {
|
||||
TokenTree::Subtree(it)
|
||||
}
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expansion_does_not_parse_as_expression() {
|
||||
check(
|
||||
@ -52,9 +91,9 @@ fn match_by_first_token_literally() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($ i:ident) => ( mod $ i {} );
|
||||
(= $ i:ident) => ( fn $ i() {} );
|
||||
(+ $ i:ident) => ( struct $ i; )
|
||||
($i:ident) => ( mod $i {} );
|
||||
(= $i:ident) => ( fn $i() {} );
|
||||
(+ $i:ident) => ( struct $i; )
|
||||
}
|
||||
m! { foo }
|
||||
m! { = bar }
|
||||
@ -62,9 +101,9 @@ m! { + Baz }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($ i:ident) => ( mod $ i {} );
|
||||
(= $ i:ident) => ( fn $ i() {} );
|
||||
(+ $ i:ident) => ( struct $ i; )
|
||||
($i:ident) => ( mod $i {} );
|
||||
(= $i:ident) => ( fn $i() {} );
|
||||
(+ $i:ident) => ( struct $i; )
|
||||
}
|
||||
mod foo {}
|
||||
fn bar() {}
|
||||
@ -78,9 +117,9 @@ fn match_by_last_token_literally() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($ i:ident) => ( mod $ i {} );
|
||||
($ i:ident =) => ( fn $ i() {} );
|
||||
($ i:ident +) => ( struct $ i; )
|
||||
($i:ident) => ( mod $i {} );
|
||||
($i:ident =) => ( fn $i() {} );
|
||||
($i:ident +) => ( struct $i; )
|
||||
}
|
||||
m! { foo }
|
||||
m! { bar = }
|
||||
@ -88,9 +127,9 @@ m! { Baz + }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($ i:ident) => ( mod $ i {} );
|
||||
($ i:ident =) => ( fn $ i() {} );
|
||||
($ i:ident +) => ( struct $ i; )
|
||||
($i:ident) => ( mod $i {} );
|
||||
($i:ident =) => ( fn $i() {} );
|
||||
($i:ident +) => ( struct $i; )
|
||||
}
|
||||
mod foo {}
|
||||
fn bar() {}
|
||||
@ -104,9 +143,9 @@ fn match_by_ident() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($ i:ident) => ( mod $ i {} );
|
||||
(spam $ i:ident) => ( fn $ i() {} );
|
||||
(eggs $ i:ident) => ( struct $ i; )
|
||||
($i:ident) => ( mod $i {} );
|
||||
(spam $i:ident) => ( fn $i() {} );
|
||||
(eggs $i:ident) => ( struct $i; )
|
||||
}
|
||||
m! { foo }
|
||||
m! { spam bar }
|
||||
@ -114,9 +153,9 @@ m! { eggs Baz }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($ i:ident) => ( mod $ i {} );
|
||||
(spam $ i:ident) => ( fn $ i() {} );
|
||||
(eggs $ i:ident) => ( struct $ i; )
|
||||
($i:ident) => ( mod $i {} );
|
||||
(spam $i:ident) => ( fn $i() {} );
|
||||
(eggs $i:ident) => ( struct $i; )
|
||||
}
|
||||
mod foo {}
|
||||
fn bar() {}
|
||||
@ -130,9 +169,9 @@ fn match_by_separator_token() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($ ($ i:ident),*) => ($ ( mod $ i {} )*);
|
||||
($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
|
||||
($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
|
||||
($($i:ident),*) => ($(mod $i {} )*);
|
||||
($($i:ident)#*) => ($(fn $i() {} )*);
|
||||
($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
|
||||
}
|
||||
|
||||
m! { foo, bar }
|
||||
@ -143,9 +182,9 @@ m! { Foo,# Bar }
|
||||
"#,
|
||||
expect![[r##"
|
||||
macro_rules! m {
|
||||
($ ($ i:ident),*) => ($ ( mod $ i {} )*);
|
||||
($ ($ i:ident)#*) => ($ ( fn $ i() {} )*);
|
||||
($ i:ident ,# $ j:ident) => ( struct $ i; struct $ j; )
|
||||
($($i:ident),*) => ($(mod $i {} )*);
|
||||
($($i:ident)#*) => ($(fn $i() {} )*);
|
||||
($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
|
||||
}
|
||||
|
||||
mod foo {}
|
||||
@ -159,3 +198,188 @@ struct Bar;
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_pattern_with_multiple_defs() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
|
||||
}
|
||||
m! { foo, bar }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
|
||||
}
|
||||
impl Bar {
|
||||
fn foo() {}
|
||||
fn bar() {}
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_pattern_with_multiple_statement() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($($i:ident),*) => ( fn baz() { $($i ();)* } );
|
||||
}
|
||||
m! { foo, bar }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($($i:ident),*) => ( fn baz() { $($i ();)* } );
|
||||
}
|
||||
fn baz() {
|
||||
foo();
|
||||
bar();
|
||||
}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_pattern_with_multiple_statement_without_semi() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($($i:ident),*) => ( fn baz() { $($i() );* } );
|
||||
}
|
||||
m! { foo, bar }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($($i:ident),*) => ( fn baz() { $($i() );* } );
|
||||
}
|
||||
fn baz() {
|
||||
foo();
|
||||
bar()
|
||||
}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_empty_fixed_token() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
|
||||
}
|
||||
m!{#abc}
|
||||
"#,
|
||||
expect![[r##"
|
||||
macro_rules! m {
|
||||
($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
|
||||
}
|
||||
fn baz() {}
|
||||
"##]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_in_subtree() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
(fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
|
||||
}
|
||||
m! { fn baz { a b } }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
(fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
|
||||
}
|
||||
fn baz() {
|
||||
a();
|
||||
b();
|
||||
}
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_order() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
($ i:expr) => { fn bar() { $ i * 3; } }
|
||||
}
|
||||
// +tree
|
||||
m! { 1 + 2 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
($ i:expr) => { fn bar() { $ i * 3; } }
|
||||
}
|
||||
fn bar() {
|
||||
1+2*3;
|
||||
}
|
||||
// MACRO_ITEMS@0..15
|
||||
// FN@0..15
|
||||
// FN_KW@0..2 "fn"
|
||||
// NAME@2..5
|
||||
// IDENT@2..5 "bar"
|
||||
// PARAM_LIST@5..7
|
||||
// L_PAREN@5..6 "("
|
||||
// R_PAREN@6..7 ")"
|
||||
// BLOCK_EXPR@7..15
|
||||
// STMT_LIST@7..15
|
||||
// L_CURLY@7..8 "{"
|
||||
// EXPR_STMT@8..14
|
||||
// BIN_EXPR@8..13
|
||||
// BIN_EXPR@8..11
|
||||
// LITERAL@8..9
|
||||
// INT_NUMBER@8..9 "1"
|
||||
// PLUS@9..10 "+"
|
||||
// LITERAL@10..11
|
||||
// INT_NUMBER@10..11 "2"
|
||||
// STAR@11..12 "*"
|
||||
// LITERAL@12..13
|
||||
// INT_NUMBER@12..13 "3"
|
||||
// SEMICOLON@13..14 ";"
|
||||
// R_CURLY@14..15 "}"
|
||||
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_with_multichar_sep() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
(fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
|
||||
}
|
||||
m! (fn baz { true false } );
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
(fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
|
||||
}
|
||||
fn baz() -> bool {
|
||||
true && false
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m {
|
||||
(fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
|
||||
}
|
||||
m! (fn baz { true && false } );
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m {
|
||||
(fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
|
||||
}
|
||||
fn baz() -> bool {
|
||||
true && false
|
||||
}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -8,18 +8,18 @@ use crate::macro_expansion_tests::check;
|
||||
fn unary_minus_is_a_literal() {
|
||||
check(
|
||||
r#"
|
||||
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
|
||||
macro_rules! m { ($x:literal) => (literal!();); ($x:tt) => (not_a_literal!();); }
|
||||
m!(92);
|
||||
m!(-92);
|
||||
m!(-9.2);
|
||||
m!(--92);
|
||||
"#,
|
||||
expect![[r#"
|
||||
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
|
||||
literal!()
|
||||
literal!()
|
||||
literal!()
|
||||
/* error: leftover tokens */not_a_literal!()
|
||||
macro_rules! m { ($x:literal) => (literal!();); ($x:tt) => (not_a_literal!();); }
|
||||
literal!();
|
||||
literal!();
|
||||
literal!();
|
||||
/* error: leftover tokens */not_a_literal!();
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ macro_rules! m {
|
||||
($($i:ident)*) => ($_);
|
||||
($($true:ident)*) => ($true);
|
||||
($($false:ident)*) => ($false);
|
||||
($) => ($);
|
||||
($) => (m!($););
|
||||
}
|
||||
m!($);
|
||||
"#,
|
||||
@ -29,9 +29,9 @@ macro_rules! m {
|
||||
($($i:ident)*) => ($_);
|
||||
($($true:ident)*) => ($true);
|
||||
($($false:ident)*) => ($false);
|
||||
($) => ($);
|
||||
($) => (m!($););
|
||||
}
|
||||
$
|
||||
m!($);
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ mbe = { path = "../mbe", version = "0.0.0" }
|
||||
limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
@ -33,7 +33,7 @@ limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.2", default-features = false, features = [
|
||||
"env-filter",
|
||||
|
@ -38,4 +38,4 @@ hir = { path = "../hir", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
@ -25,4 +25,4 @@ hir = { path = "../hir", version = "0.0.0" }
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
sourcegen = { path = "../sourcegen" }
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
@ -28,7 +28,7 @@ profile = { path = "../profile", version = "0.0.0" }
|
||||
hir = { path = "../hir", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
xshell = "0.1"
|
||||
|
||||
test_utils = { path = "../test_utils" }
|
||||
|
@ -31,4 +31,4 @@ limit = { path = "../limit", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
@ -23,7 +23,7 @@ hir = { path = "../hir", version = "0.0.0" }
|
||||
ide_db = { path = "../ide_db", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
||||
test_utils = { path = "../test_utils" }
|
||||
sourcegen = { path = "../sourcegen" }
|
||||
|
@ -21,4 +21,4 @@ hir = { path = "../hir", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
test_utils = { path = "../test_utils" }
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
@ -12,7 +12,7 @@ doctest = false
|
||||
cov-mark = "2.0.0-pre.1"
|
||||
rustc-hash = "1.1.0"
|
||||
smallvec = "1.2.0"
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
tracing = "0.1"
|
||||
|
||||
syntax = { path = "../syntax", version = "0.0.0" }
|
||||
|
@ -71,235 +71,6 @@ macro_rules! foobar {
|
||||
assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_convert_tt() {
|
||||
parse_macro(r#"
|
||||
macro_rules! impl_froms {
|
||||
($e:ident: $($v:ident),*) => {
|
||||
$(
|
||||
impl From<$v> for $e {
|
||||
fn from(it: $v) -> $e {
|
||||
$e::$v(it)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
"#)
|
||||
.assert_expand_tt(
|
||||
"impl_froms!(TokenTree: Leaf, Subtree);",
|
||||
"impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
|
||||
impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_convert_tt2() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! impl_froms {
|
||||
($e:ident: $($v:ident),*) => {
|
||||
$(
|
||||
impl From<$v> for $e {
|
||||
fn from(it: $v) -> $e {
|
||||
$e::$v(it)
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.assert_expand(
|
||||
"impl_froms!(TokenTree: Leaf, Subtree);",
|
||||
r#"
|
||||
SUBTREE $
|
||||
IDENT impl 20
|
||||
IDENT From 21
|
||||
PUNCH < [joint] 22
|
||||
IDENT Leaf 53
|
||||
PUNCH > [alone] 25
|
||||
IDENT for 26
|
||||
IDENT TokenTree 51
|
||||
SUBTREE {} 29
|
||||
IDENT fn 30
|
||||
IDENT from 31
|
||||
SUBTREE () 32
|
||||
IDENT it 33
|
||||
PUNCH : [alone] 34
|
||||
IDENT Leaf 53
|
||||
PUNCH - [joint] 37
|
||||
PUNCH > [alone] 38
|
||||
IDENT TokenTree 51
|
||||
SUBTREE {} 41
|
||||
IDENT TokenTree 51
|
||||
PUNCH : [joint] 44
|
||||
PUNCH : [joint] 45
|
||||
IDENT Leaf 53
|
||||
SUBTREE () 48
|
||||
IDENT it 49
|
||||
IDENT impl 20
|
||||
IDENT From 21
|
||||
PUNCH < [joint] 22
|
||||
IDENT Subtree 55
|
||||
PUNCH > [alone] 25
|
||||
IDENT for 26
|
||||
IDENT TokenTree 51
|
||||
SUBTREE {} 29
|
||||
IDENT fn 30
|
||||
IDENT from 31
|
||||
SUBTREE () 32
|
||||
IDENT it 33
|
||||
PUNCH : [alone] 34
|
||||
IDENT Subtree 55
|
||||
PUNCH - [joint] 37
|
||||
PUNCH > [alone] 38
|
||||
IDENT TokenTree 51
|
||||
SUBTREE {} 41
|
||||
IDENT TokenTree 51
|
||||
PUNCH : [joint] 44
|
||||
PUNCH : [joint] 45
|
||||
IDENT Subtree 55
|
||||
SUBTREE () 48
|
||||
IDENT it 49
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expr_order() {
|
||||
let expanded = parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ i:expr) => {
|
||||
fn bar() { $ i * 2; }
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.expand_items("foo! { 1 + 1}");
|
||||
|
||||
let dump = format!("{:#?}", expanded);
|
||||
assert_eq_text!(
|
||||
r#"MACRO_ITEMS@0..15
|
||||
FN@0..15
|
||||
FN_KW@0..2 "fn"
|
||||
NAME@2..5
|
||||
IDENT@2..5 "bar"
|
||||
PARAM_LIST@5..7
|
||||
L_PAREN@5..6 "("
|
||||
R_PAREN@6..7 ")"
|
||||
BLOCK_EXPR@7..15
|
||||
STMT_LIST@7..15
|
||||
L_CURLY@7..8 "{"
|
||||
EXPR_STMT@8..14
|
||||
BIN_EXPR@8..13
|
||||
BIN_EXPR@8..11
|
||||
LITERAL@8..9
|
||||
INT_NUMBER@8..9 "1"
|
||||
PLUS@9..10 "+"
|
||||
LITERAL@10..11
|
||||
INT_NUMBER@10..11 "1"
|
||||
STAR@11..12 "*"
|
||||
LITERAL@12..13
|
||||
INT_NUMBER@12..13 "2"
|
||||
SEMICOLON@13..14 ";"
|
||||
R_CURLY@14..15 "}""#,
|
||||
dump.trim()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_pattern_with_multiple_defs() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ ($ i:ident),*) => ( struct Bar { $ (
|
||||
fn $ i {}
|
||||
)*} );
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_pattern_with_multiple_statement() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ ($ i:ident),*) => ( fn baz { $ (
|
||||
$ i ();
|
||||
)*} );
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_pattern_with_multiple_statement_without_semi() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ ($ i:ident),*) => ( fn baz { $ (
|
||||
$i()
|
||||
);*} );
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_empty_fixed_token() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
($ ($ i:ident)* #abc) => ( fn baz { $ (
|
||||
$ i ();
|
||||
)*} );
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.assert_expand_items("foo! {#abc}", "fn baz {}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_in_subtree() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
(fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
|
||||
$ i ();
|
||||
)*} );
|
||||
}"#,
|
||||
)
|
||||
.assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_with_multichar_sep() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
(fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
|
||||
}"#,
|
||||
)
|
||||
.assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_with_multichar_sep2() {
|
||||
parse_macro(
|
||||
r#"
|
||||
macro_rules! foo {
|
||||
(fn $name:ident {$($i:literal)&&*} ) => ( fn $name() -> bool { $($i)&&*} );
|
||||
}"#,
|
||||
)
|
||||
.assert_expand_items("foo! (fn baz {true && true} );", "fn baz () -> bool {true &&true}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_match_group_zero_match() {
|
||||
parse_macro(
|
||||
|
@ -25,7 +25,7 @@ paths = { path = "../paths", version = "0.0.0" }
|
||||
proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.1.0"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
|
||||
# used as proc macro test targets
|
||||
proc_macro_test = { path = "../proc_macro_test" }
|
||||
|
@ -16,7 +16,7 @@ semver = "1"
|
||||
serde = { version = "1.0.106", features = ["derive"] }
|
||||
serde_json = "1.0.48"
|
||||
anyhow = "1.0.26"
|
||||
expect-test = "1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
la-arena = { version = "0.2.0", path = "../../lib/arena" }
|
||||
|
||||
cfg = { path = "../cfg", version = "0.0.0" }
|
||||
|
@ -67,7 +67,7 @@ winapi = "0.3.8"
|
||||
jemallocator = { version = "0.4.1", package = "tikv-jemallocator", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
xshell = "0.1"
|
||||
|
||||
test_utils = { path = "../test_utils" }
|
||||
|
@ -26,7 +26,7 @@ profile = { path = "../profile", version = "0.0.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
rayon = "1"
|
||||
expect-test = "1.1"
|
||||
expect-test = "1.2.0-pre.1"
|
||||
proc-macro2 = "1.0.8"
|
||||
quote = "1.0.2"
|
||||
ungrammar = "=1.14.8"
|
||||
|
@ -89,6 +89,9 @@ impl<T> Parse<T> {
|
||||
pub fn syntax_node(&self) -> SyntaxNode {
|
||||
SyntaxNode::new_root(self.green.clone())
|
||||
}
|
||||
pub fn errors(&self) -> &[SyntaxError] {
|
||||
&*self.errors
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AstNode> Parse<T> {
|
||||
@ -100,10 +103,6 @@ impl<T: AstNode> Parse<T> {
|
||||
T::cast(self.syntax_node()).unwrap()
|
||||
}
|
||||
|
||||
pub fn errors(&self) -> &[SyntaxError] {
|
||||
&*self.errors
|
||||
}
|
||||
|
||||
pub fn ok(self) -> Result<T, Arc<Vec<SyntaxError>>> {
|
||||
if self.errors.is_empty() {
|
||||
Ok(self.tree())
|
||||
|
Loading…
x
Reference in New Issue
Block a user