Skip to content

Commit 22ccb1a

Browse files
bors[bot]matklad
andauthored
Merge #11141
11141: internal: add tests for extra parser entry points r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents e279d52 + 2f32379 commit 22ccb1a

File tree

7 files changed

+135
-31
lines changed

7 files changed

+135
-31
lines changed

crates/hir_def/src/macro_expansion_tests/mbe/matching.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,56 @@ macro_rules! m{ ($fmt:expr) => (); }
5050
"#]],
5151
);
5252
}
53+
54+
#[test]
55+
fn asi() {
56+
// Thanks, Christopher!
57+
//
58+
// https://internals.rust-lang.org/t/understanding-decisions-behind-semicolons/15181/29
59+
check(
60+
r#"
61+
macro_rules! asi { ($($stmt:stmt)*) => ($($stmt)*); }
62+
63+
fn main() {
64+
asi! {
65+
let a = 2
66+
let b = 5
67+
drop(b-a)
68+
println!("{}", a+b)
69+
}
70+
}
71+
"#,
72+
expect![[r#"
73+
macro_rules! asi { ($($stmt:stmt)*) => ($($stmt)*); }
74+
75+
fn main() {
76+
let a = 2let b = 5drop(b-a)println!("{}", a+b)
77+
}
78+
"#]],
79+
)
80+
}
81+
82+
#[test]
83+
fn stmt_boundaries() {
84+
// FIXME: this actually works OK under rustc.
85+
check(
86+
r#"
87+
macro_rules! m {
88+
($($s:stmt)*) => (stringify!($($s |)*);)
89+
}
90+
m!(;;92;let x = 92; loop {};);
91+
"#,
92+
expect![[r#"
93+
macro_rules! m {
94+
($($s:stmt)*) => (stringify!($($s |)*);)
95+
}
96+
stringify!(;
97+
|;
98+
|92|;
99+
|let x = 92|;
100+
|loop {}
101+
|;
102+
|);
103+
"#]],
104+
);
105+
}

crates/parser/src/grammar.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub(crate) mod entry {
5959
}
6060

6161
pub(crate) fn stmt(p: &mut Parser) {
62-
expressions::stmt(p, expressions::StmtWithSemi::No, true);
62+
expressions::stmt(p, expressions::Semicolon::Forbidden);
6363
}
6464

6565
pub(crate) fn pat(p: &mut Parser) {
@@ -98,12 +98,7 @@ pub(crate) mod entry {
9898
let m = p.start();
9999

100100
while !p.at(EOF) {
101-
if p.at(T![;]) {
102-
p.bump(T![;]);
103-
continue;
104-
}
105-
106-
expressions::stmt(p, expressions::StmtWithSemi::Optional, true);
101+
expressions::stmt(p, expressions::Semicolon::Optional);
107102
}
108103

109104
m.complete(p, MACRO_STMTS);

crates/parser/src/grammar/expressions.rs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ use super::*;
55
pub(crate) use self::atom::{block_expr, match_arm_list};
66
pub(super) use self::atom::{literal, LITERAL_FIRST};
77

8-
pub(super) enum StmtWithSemi {
9-
Yes,
10-
No,
8+
#[derive(PartialEq, Eq)]
9+
pub(super) enum Semicolon {
10+
Required,
1111
Optional,
12+
Forbidden,
1213
}
1314

1415
const EXPR_FIRST: TokenSet = LHS_FIRST;
@@ -28,7 +29,11 @@ fn expr_no_struct(p: &mut Parser) {
2829
expr_bp(p, None, r, 1);
2930
}
3031

31-
pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
32+
pub(super) fn stmt(p: &mut Parser, semicolon: Semicolon) {
33+
if p.eat(T![;]) {
34+
return;
35+
}
36+
3237
let m = p.start();
3338
// test attr_on_expr_stmt
3439
// fn foo() {
@@ -40,7 +45,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
4045
attributes::outer_attrs(p);
4146

4247
if p.at(T![let]) {
43-
let_stmt(p, m, with_semi);
48+
let_stmt(p, m, semicolon);
4449
return;
4550
}
4651

@@ -52,7 +57,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
5257
};
5358

5459
if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
55-
if !(p.at(T!['}']) || (prefer_expr && p.at(EOF))) {
60+
if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) {
5661
// test no_semi_after_block
5762
// fn foo() {
5863
// if true {}
@@ -68,27 +73,26 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
6873
// test!{}
6974
// }
7075
let m = cm.precede(p);
71-
match with_semi {
72-
StmtWithSemi::No => (),
73-
StmtWithSemi::Optional => {
74-
p.eat(T![;]);
75-
}
76-
StmtWithSemi::Yes => {
76+
match semicolon {
77+
Semicolon::Required => {
7778
if blocklike.is_block() {
7879
p.eat(T![;]);
7980
} else {
8081
p.expect(T![;]);
8182
}
8283
}
84+
Semicolon::Optional => {
85+
p.eat(T![;]);
86+
}
87+
Semicolon::Forbidden => (),
8388
}
84-
8589
m.complete(p, EXPR_STMT);
8690
}
8791
}
8892

8993
// test let_stmt
9094
// fn f() { let x: i32 = 92; }
91-
fn let_stmt(p: &mut Parser, m: Marker, with_semi: StmtWithSemi) {
95+
fn let_stmt(p: &mut Parser, m: Marker, with_semi: Semicolon) {
9296
p.bump(T![let]);
9397
patterns::pattern(p);
9498
if p.at(T![:]) {
@@ -113,11 +117,11 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
113117
}
114118

115119
match with_semi {
116-
StmtWithSemi::No => (),
117-
StmtWithSemi::Optional => {
120+
Semicolon::Forbidden => (),
121+
Semicolon::Optional => {
118122
p.eat(T![;]);
119123
}
120-
StmtWithSemi::Yes => {
124+
Semicolon::Required => {
121125
p.expect(T![;]);
122126
}
123127
}
@@ -143,13 +147,7 @@ pub(super) fn expr_block_contents(p: &mut Parser) {
143147
// fn f() {};
144148
// struct S {};
145149
// }
146-
147-
if p.at(T![;]) {
148-
p.bump(T![;]);
149-
continue;
150-
}
151-
152-
stmt(p, StmtWithSemi::Yes, false);
150+
stmt(p, Semicolon::Required);
153151
}
154152
}
155153

crates/parser/src/output.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub struct Output {
2222
error: Vec<String>,
2323
}
2424

25+
#[derive(Debug)]
2526
pub enum Step<'a> {
2627
Token { kind: SyntaxKind, n_input_tokens: u8 },
2728
Enter { kind: SyntaxKind },

crates/parser/src/shortcuts.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::{
1616
SyntaxKind::{self, *},
1717
};
1818

19+
#[derive(Debug)]
1920
pub enum StrStep<'a> {
2021
Token { kind: SyntaxKind, text: &'a str },
2122
Enter { kind: SyntaxKind },
@@ -49,6 +50,7 @@ impl<'a> LexedStr<'a> {
4950
res
5051
}
5152

53+
/// NB: only valid to call with Output from Reparser/TopLevelEntry.
5254
pub fn intersperse_trivia(
5355
&self,
5456
output: &crate::Output,

crates/parser/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod sourcegen_inline_tests;
2+
mod entries;
23

34
use std::{
45
fmt::Write,

crates/parser/src/tests/entries.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use crate::{LexedStr, PrefixEntryPoint, Step};
2+
3+
#[test]
4+
fn vis() {
5+
check_prefix(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
6+
check_prefix(PrefixEntryPoint::Vis, "fn foo() {}", "");
7+
check_prefix(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
8+
check_prefix(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
9+
check_prefix(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
10+
}
11+
12+
#[test]
13+
fn block() {
14+
check_prefix(PrefixEntryPoint::Block, "{}, 92", "{}");
15+
check_prefix(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
16+
check_prefix(PrefixEntryPoint::Block, "()", "");
17+
}
18+
19+
#[test]
20+
fn stmt() {
21+
check_prefix(PrefixEntryPoint::Stmt, "92; fn", "92");
22+
check_prefix(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
23+
check_prefix(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
24+
check_prefix(PrefixEntryPoint::Stmt, ";;;", ";");
25+
check_prefix(PrefixEntryPoint::Stmt, "+", "+");
26+
check_prefix(PrefixEntryPoint::Stmt, "@", "@");
27+
check_prefix(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
28+
}
29+
30+
fn check_prefix(entry: PrefixEntryPoint, input: &str, prefix: &str) {
31+
let lexed = LexedStr::new(input);
32+
let input = lexed.to_input();
33+
34+
let mut n_tokens = 0;
35+
for step in entry.parse(&input).iter() {
36+
match step {
37+
Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
38+
Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
39+
}
40+
}
41+
42+
let mut i = 0;
43+
loop {
44+
if n_tokens == 0 {
45+
break;
46+
}
47+
if !lexed.kind(i).is_trivia() {
48+
n_tokens -= 1;
49+
}
50+
i += 1;
51+
}
52+
let buf = &lexed.as_str()[..lexed.text_start(i)];
53+
assert_eq!(buf, prefix);
54+
}

0 commit comments

Comments
 (0)