Skip to content

Commit 27c5169

Browse files
committed
Add test for delim bug
1 parent 92b561b commit 27c5169

File tree

2 files changed

+147
-12
lines changed

2 files changed

+147
-12
lines changed

crates/ra_mbe/src/syntax_bridge.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,108 @@ struct RawConvertor<'a> {
267267
inner: std::slice::Iter<'a, Token>,
268268
}
269269

270+
trait SrcToken {
271+
fn kind() -> SyntaxKind;
272+
}
273+
274+
trait TokenConvertor {
275+
type Token : SrcToken;
276+
277+
fn go(&mut self) -> Option<tt::Subtree> {
278+
let mut subtree = tt::Subtree::default();
279+
subtree.delimiter = None;
280+
while self.peek().is_some() {
281+
self.collect_leaf(&mut subtree.token_trees);
282+
}
283+
if subtree.token_trees.is_empty() {
284+
return None;
285+
}
286+
if subtree.token_trees.len() == 1 {
287+
if let tt::TokenTree::Subtree(first) = &subtree.token_trees[0] {
288+
return Some(first.clone());
289+
}
290+
}
291+
Some(subtree)
292+
}
293+
294+
fn bump(&mut self) -> Option<(Self::Token, TextRange)>;
295+
296+
fn peek(&self) -> Option<Self::Token>;
297+
298+
fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) {
299+
let (token, range) = match self.bump() {
300+
None => return,
301+
Some(it) => it,
302+
};
303+
304+
let k: SyntaxKind = token.kind();
305+
if k == COMMENT {
306+
let node = doc_comment(&self.text[range]);
307+
if let Some(tokens) = convert_doc_comment(&node) {
308+
result.extend(tokens);
309+
}
310+
return;
311+
}
312+
313+
result.push(if k.is_punct() {
314+
let delim = match k {
315+
T!['('] => Some((tt::DelimiterKind::Parenthesis, T![')'])),
316+
T!['{'] => Some((tt::DelimiterKind::Brace, T!['}'])),
317+
T!['['] => Some((tt::DelimiterKind::Bracket, T![']'])),
318+
_ => None,
319+
};
320+
321+
if let Some((kind, closed)) = delim {
322+
let mut subtree = tt::Subtree::default();
323+
let id = self.id_alloc.open_delim(range);
324+
subtree.delimiter = Some(tt::Delimiter { kind, id });
325+
326+
while self.peek().map(|it| it.kind != closed).unwrap_or(false) {
327+
self.collect_leaf(&mut subtree.token_trees);
328+
}
329+
let last_range = match self.bump() {
330+
None => return,
331+
Some(it) => it.1,
332+
};
333+
self.id_alloc.close_delim(id, last_range);
334+
subtree.into()
335+
} else {
336+
let spacing = match self.peek() {
337+
Some(next)
338+
if next.kind.is_trivia()
339+
|| next.kind == T!['[']
340+
|| next.kind == T!['{']
341+
|| next.kind == T!['('] =>
342+
{
343+
tt::Spacing::Alone
344+
}
345+
Some(next) if next.kind.is_punct() => tt::Spacing::Joint,
346+
_ => tt::Spacing::Alone,
347+
};
348+
let char =
349+
self.text[range].chars().next().expect("Token from lexer must be single char");
350+
351+
tt::Leaf::from(tt::Punct { char, spacing, id: self.id_alloc.alloc(range) }).into()
352+
}
353+
} else {
354+
macro_rules! make_leaf {
355+
($i:ident) => {
356+
tt::$i { id: self.id_alloc.alloc(range), text: self.text[range].into() }.into()
357+
};
358+
}
359+
let leaf: tt::Leaf = match k {
360+
T![true] | T![false] => make_leaf!(Literal),
361+
IDENT | LIFETIME => make_leaf!(Ident),
362+
k if k.is_keyword() => make_leaf!(Ident),
363+
k if k.is_literal() => make_leaf!(Literal),
364+
_ => return,
365+
};
366+
367+
leaf.into()
368+
});
369+
}
370+
}
371+
270372
impl RawConvertor<'_> {
271373
fn go(&mut self) -> Option<tt::Subtree> {
272374
let mut subtree = tt::Subtree::default();
@@ -295,6 +397,7 @@ impl RawConvertor<'_> {
295397
fn peek(&self) -> Option<Token> {
296398
self.inner.as_slice().get(0).cloned()
297399
}
400+
298401

299402
fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) {
300403
let (token, range) = match self.bump() {

crates/ra_mbe/src/tests.rs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -427,22 +427,28 @@ MACRO_ITEMS@[0; 40)
427427
);
428428
}
429429

430-
#[test]
431-
fn test_expand_literals_to_token_tree() {
432-
fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree {
433-
if let tt::TokenTree::Subtree(subtree) = tt {
434-
return &subtree;
435-
}
436-
unreachable!("It is not a subtree");
430+
fn to_subtree(tt: &tt::TokenTree) -> &tt::Subtree {
431+
if let tt::TokenTree::Subtree(subtree) = tt {
432+
return &subtree;
437433
}
434+
unreachable!("It is not a subtree");
435+
}
436+
fn to_literal(tt: &tt::TokenTree) -> &tt::Literal {
437+
if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt {
438+
return lit;
439+
}
440+
unreachable!("It is not a literal");
441+
}
438442

439-
fn to_literal(tt: &tt::TokenTree) -> &tt::Literal {
440-
if let tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) = tt {
441-
return lit;
442-
}
443-
unreachable!("It is not a literal");
443+
fn to_punct(tt: &tt::TokenTree) -> &tt::Punct {
444+
if let tt::TokenTree::Leaf(tt::Leaf::Punct(lit)) = tt {
445+
return lit;
444446
}
447+
unreachable!("It is not a Punct");
448+
}
445449

450+
#[test]
451+
fn test_expand_literals_to_token_tree() {
446452
let expansion = parse_macro(
447453
r#"
448454
macro_rules! literals {
@@ -470,6 +476,22 @@ fn test_expand_literals_to_token_tree() {
470476
assert_eq!(to_literal(&stm_tokens[15 + 3]).text, "\"rust1\"");
471477
}
472478

479+
#[test]
480+
fn test_attr_to_token_tree() {
481+
let expansion = parse_to_token_tree_by_syntax(
482+
r#"
483+
#[derive(Copy)]
484+
struct Foo;
485+
"#,
486+
);
487+
488+
assert_eq!(to_punct(&expansion.token_trees[0]).char, '#');
489+
assert_eq!(
490+
to_subtree(&expansion.token_trees[1]).delimiter_kind(),
491+
Some(tt::DelimiterKind::Bracket)
492+
);
493+
}
494+
473495
#[test]
474496
fn test_two_idents() {
475497
parse_macro(
@@ -1517,6 +1539,16 @@ pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture {
15171539
MacroFixture { rules }
15181540
}
15191541

1542+
pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree {
1543+
let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
1544+
let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0;
1545+
1546+
let parsed = parse_to_token_tree(ra_fixture).unwrap().0;
1547+
assert_eq!(tt, parsed);
1548+
1549+
parsed
1550+
}
1551+
15201552
fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
15211553
let mut level = 0;
15221554
let mut buf = String::new();

0 commit comments

Comments
 (0)