From ffed132e52964f029a586a3efd4afc879ed39c59 Mon Sep 17 00:00:00 2001 From: pcpthm Date: Tue, 19 Mar 2019 17:24:02 +0900 Subject: Allow attributes on top level expression A top level expression is either - a expression statement or - the last expression in a block --- crates/ra_parser/src/event.rs | 4 +- crates/ra_parser/src/grammar/expressions.rs | 83 +++++++++++++++--------- crates/ra_parser/src/grammar/expressions/atom.rs | 4 +- crates/ra_parser/src/parser.rs | 23 +++++++ 4 files changed, 79 insertions(+), 35 deletions(-) (limited to 'crates/ra_parser') diff --git a/crates/ra_parser/src/event.rs b/crates/ra_parser/src/event.rs index 6361d5d86..c1773e8e0 100644 --- a/crates/ra_parser/src/event.rs +++ b/crates/ra_parser/src/event.rs @@ -105,7 +105,9 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec) { // append `A`'s forward_parent `B` fp = match mem::replace(&mut events[idx], Event::tombstone()) { Event::Start { kind, forward_parent } => { - forward_parents.push(kind); + if kind != TOMBSTONE { + forward_parents.push(kind); + } forward_parent } _ => unreachable!(), diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index 83812e938..e35c46a5e 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; pub(super) fn expr(p: &mut Parser) -> BlockLike { let r = Restrictions { forbid_structs: false, prefer_stmt: false }; - expr_bp(p, r, 1) + expr_bp(p, r, 1).1 } -pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike { +pub(super) fn expr_stmt(p: &mut Parser) -> (Option, BlockLike) { let r = Restrictions { forbid_structs: false, prefer_stmt: true }; expr_bp(p, r, 1) } @@ -55,7 +55,13 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { // test block_items // fn a() { fn b() {} } let m = p.start(); - let has_attrs = p.at(POUND); + // test attr_on_expr_stmt + // fn foo() { + // #[A] foo(); + // #[B] bar!{} + // #[C] #[D] {} + // #[D] return (); + // } attributes::outer_attributes(p); if p.at(LET_KW) { let_stmt(p, m); @@ -67,35 +73,48 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { Err(m) => m, }; - if has_attrs { - m.abandon(p); - p.error("expected a let statement or an item after attributes in block"); - } else { - let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block; - if p.at(R_CURLY) { - m.abandon(p); - } else { - // test no_semi_after_block - // fn foo() { - // if true {} - // loop {} - // match () {} - // while true {} - // for _ in () {} - // {} - // {} - // macro_rules! test { - // () => {} - // } - // test!{} - // } - if is_blocklike { - p.eat(SEMI); + let (cm, blocklike) = expr_stmt(p); + let cm = match cm { + None => { + if p.at(R_CURLY) { + m.abandon(p); } else { p.expect(SEMI); + m.complete(p, EXPR_STMT); } - m.complete(p, EXPR_STMT); + continue; + } + Some(cm) => cm, + }; + + if p.at(R_CURLY) { + // test attr_on_last_expr_in_block + // fn foo() { + // { #[A] bar!()? } + // #[B] &() + // } + m.contract_child(p, cm); + } else { + // test no_semi_after_block + // fn foo() { + // if true {} + // loop {} + // match () {} + // while true {} + // for _ in () {} + // {} + // {} + // macro_rules! test { + // () => {} + // } + // test!{} + // } + if blocklike.is_block() { + p.eat(SEMI); + } else { + p.expect(SEMI); } + m.complete(p, EXPR_STMT); } } @@ -176,7 +195,7 @@ fn current_op(p: &Parser) -> (u8, Op) { } // Parses expression with binding power of at least bp. -fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { +fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option, BlockLike) { let mut lhs = match lhs(p, r) { Some((lhs, blocklike)) => { // test stmt_bin_expr_ambiguity @@ -185,11 +204,11 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { // {1} &2; // } if r.prefer_stmt && blocklike.is_block() { - return BlockLike::Block; + return (Some(lhs), BlockLike::Block); } lhs } - None => return BlockLike::NotBlock, + None => return (None, BlockLike::NotBlock), }; loop { @@ -208,7 +227,7 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike { expr_bp(p, r, op_bp + 1); lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR }); } - BlockLike::NotBlock + (Some(lhs), BlockLike::NotBlock) } const LHS_FIRST: TokenSet = diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs index d933288cd..a23977bfb 100644 --- a/crates/ra_parser/src/grammar/expressions/atom.rs +++ b/crates/ra_parser/src/grammar/expressions/atom.rs @@ -392,9 +392,9 @@ fn match_arm(p: &mut Parser) -> BlockLike { match_guard(p); } p.expect(FAT_ARROW); - let ret = expr_stmt(p); + let blocklike = expr_stmt(p).1; m.complete(p, MATCH_ARM); - ret + blocklike } // test match_guard diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs index a18458148..702669eb9 100644 --- a/crates/ra_parser/src/parser.rs +++ b/crates/ra_parser/src/parser.rs @@ -228,6 +228,29 @@ impl Marker { } } } + + /// Contract a node `cm` and complete as `cm`'s `kind`. + /// `cm` must be a child of `m` to work correctly. + /// ``` + /// m--A m--A + /// +--cm--B -> +--B + /// +--C C + /// + /// [m: TOMBSTONE, A, cm: Start(k), B, Finish, C] + /// [m: Start(k), A, cm: TOMBSTONE, B, Finish, C] + /// ``` + pub(crate) fn contract_child(mut self, p: &mut Parser, cm: CompletedMarker) -> CompletedMarker { + self.bomb.defuse(); + match p.events[self.pos as usize] { + Event::Start { kind: ref mut slot, .. } => *slot = cm.kind(), + _ => unreachable!(), + }; + match p.events[cm.0 as usize] { + Event::Start { kind: ref mut slot, .. } => *slot = TOMBSTONE, + _ => unreachable!(), + }; + CompletedMarker::new(self.pos, cm.kind()) + } } pub(crate) struct CompletedMarker(u32, SyntaxKind); -- cgit v1.2.3