aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_parser/src/grammar/expressions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_parser/src/grammar/expressions.rs')
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs94
1 files changed, 62 insertions, 32 deletions
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 83812e938..73e1acd5a 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -8,10 +8,10 @@ const EXPR_FIRST: TokenSet = LHS_FIRST;
8 8
9pub(super) fn expr(p: &mut Parser) -> BlockLike { 9pub(super) fn expr(p: &mut Parser) -> BlockLike {
10 let r = Restrictions { forbid_structs: false, prefer_stmt: false }; 10 let r = Restrictions { forbid_structs: false, prefer_stmt: false };
11 expr_bp(p, r, 1) 11 expr_bp(p, r, 1).1
12} 12}
13 13
14pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike { 14pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
15 let r = Restrictions { forbid_structs: false, prefer_stmt: true }; 15 let r = Restrictions { forbid_structs: false, prefer_stmt: true };
16 expr_bp(p, r, 1) 16 expr_bp(p, r, 1)
17} 17}
@@ -38,6 +38,13 @@ pub(crate) fn block(p: &mut Parser) {
38 m.complete(p, BLOCK); 38 m.complete(p, BLOCK);
39} 39}
40 40
41fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool {
42 match kind {
43 BIN_EXPR | RANGE_EXPR | IF_EXPR => false,
44 _ => true,
45 }
46}
47
41pub(crate) fn expr_block_contents(p: &mut Parser) { 48pub(crate) fn expr_block_contents(p: &mut Parser) {
42 // This is checked by a validator 49 // This is checked by a validator
43 attributes::inner_attributes(p); 50 attributes::inner_attributes(p);
@@ -55,6 +62,13 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
55 // test block_items 62 // test block_items
56 // fn a() { fn b() {} } 63 // fn a() { fn b() {} }
57 let m = p.start(); 64 let m = p.start();
65 // test attr_on_expr_stmt
66 // fn foo() {
67 // #[A] foo();
68 // #[B] bar!{}
69 // #[C] #[D] {}
70 // #[D] return ();
71 // }
58 let has_attrs = p.at(POUND); 72 let has_attrs = p.at(POUND);
59 attributes::outer_attributes(p); 73 attributes::outer_attributes(p);
60 if p.at(LET_KW) { 74 if p.at(LET_KW) {
@@ -67,35 +81,51 @@ pub(crate) fn expr_block_contents(p: &mut Parser) {
67 Err(m) => m, 81 Err(m) => m,
68 }; 82 };
69 83
70 if has_attrs { 84 let (cm, blocklike) = expr_stmt(p);
71 m.abandon(p); 85 let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);
72 p.error("expected a let statement or an item after attributes in block"); 86
73 } else { 87 if has_attrs && !is_expr_stmt_attr_allowed(kind) {
74 let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block; 88 // test_err attr_on_expr_not_allowed
75 if p.at(R_CURLY) { 89 // fn foo() {
90 // #[A] 1 + 2;
91 // #[B] if true {};
92 // }
93 p.error(format!("attributes are not allowed on {:?}", kind));
94 }
95
96 if p.at(R_CURLY) {
97 // test attr_on_last_expr_in_block
98 // fn foo() {
99 // { #[A] bar!()? }
100 // #[B] &()
101 // }
102 if let Some(cm) = cm {
103 cm.undo_completion(p).abandon(p);
104 m.complete(p, kind);
105 } else {
76 m.abandon(p); 106 m.abandon(p);
107 }
108 } else {
109 // test no_semi_after_block
110 // fn foo() {
111 // if true {}
112 // loop {}
113 // match () {}
114 // while true {}
115 // for _ in () {}
116 // {}
117 // {}
118 // macro_rules! test {
119 // () => {}
120 // }
121 // test!{}
122 // }
123 if blocklike.is_block() {
124 p.eat(SEMI);
77 } else { 125 } else {
78 // test no_semi_after_block 126 p.expect(SEMI);
79 // fn foo() {
80 // if true {}
81 // loop {}
82 // match () {}
83 // while true {}
84 // for _ in () {}
85 // {}
86 // {}
87 // macro_rules! test {
88 // () => {}
89 // }
90 // test!{}
91 // }
92 if is_blocklike {
93 p.eat(SEMI);
94 } else {
95 p.expect(SEMI);
96 }
97 m.complete(p, EXPR_STMT);
98 } 127 }
128 m.complete(p, EXPR_STMT);
99 } 129 }
100 } 130 }
101 131
@@ -176,7 +206,7 @@ fn current_op(p: &Parser) -> (u8, Op) {
176} 206}
177 207
178// Parses expression with binding power of at least bp. 208// Parses expression with binding power of at least bp.
179fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { 209fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
180 let mut lhs = match lhs(p, r) { 210 let mut lhs = match lhs(p, r) {
181 Some((lhs, blocklike)) => { 211 Some((lhs, blocklike)) => {
182 // test stmt_bin_expr_ambiguity 212 // test stmt_bin_expr_ambiguity
@@ -185,11 +215,11 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
185 // {1} &2; 215 // {1} &2;
186 // } 216 // }
187 if r.prefer_stmt && blocklike.is_block() { 217 if r.prefer_stmt && blocklike.is_block() {
188 return BlockLike::Block; 218 return (Some(lhs), BlockLike::Block);
189 } 219 }
190 lhs 220 lhs
191 } 221 }
192 None => return BlockLike::NotBlock, 222 None => return (None, BlockLike::NotBlock),
193 }; 223 };
194 224
195 loop { 225 loop {
@@ -208,7 +238,7 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
208 expr_bp(p, r, op_bp + 1); 238 expr_bp(p, r, op_bp + 1);
209 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); 239 lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
210 } 240 }
211 BlockLike::NotBlock 241 (Some(lhs), BlockLike::NotBlock)
212} 242}
213 243
214const LHS_FIRST: TokenSet = 244const LHS_FIRST: TokenSet =