Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions crates/hir_def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -650,8 +650,10 @@ impl ExprCollector<'_> {
self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
}
ast::Stmt::ExprStmt(stmt) => {
if self.check_cfg(&stmt).is_none() {
return;
if let Some(expr) = stmt.expr() {
if self.check_cfg(&expr).is_none() {
return;
}
}
let has_semi = stmt.semicolon_token().is_some();
// Note that macro could be expended to multiple statements
Expand Down
10 changes: 4 additions & 6 deletions crates/parser/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {

for i in 0..events.len() {
match mem::replace(&mut events[i], Event::tombstone()) {
Event::Start { kind: TOMBSTONE, .. } => (),

Event::Start { kind, forward_parent } => {
// For events[A, B, C], B is A's forward_parent, C is B's forward_parent,
// in the normal control flow, the parent-child relation: `A -> B -> C`,
Expand All @@ -109,9 +107,7 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
// append `A`'s forward_parent `B`
fp = match mem::replace(&mut events[idx], Event::tombstone()) {
Event::Start { kind, forward_parent } => {
if kind != TOMBSTONE {
forward_parents.push(kind);
}
forward_parents.push(kind);
forward_parent
}
_ => unreachable!(),
Expand All @@ -120,7 +116,9 @@ pub(super) fn process(sink: &mut dyn TreeSink, mut events: Vec<Event>) {
}

for kind in forward_parents.drain(..).rev() {
sink.start_node(kind);
if kind != TOMBSTONE {
sink.start_node(kind);
}
}
}
Event::Finish => sink.finish_node(),
Expand Down
2 changes: 1 addition & 1 deletion crates/parser/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub(crate) mod entry_points {
pub(crate) use types::type_;

pub(crate) fn expr(p: &mut Parser) {
let _ = expressions::expr_with_attrs(p);
let _ = expressions::expr(p);
}

pub(crate) fn stmt(p: &mut Parser) {
Expand Down
2 changes: 1 addition & 1 deletion crates/parser/src/grammar/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub(super) fn meta(p: &mut Parser) {
match p.current() {
T![=] => {
p.bump(T![=]);
if expressions::expr(p).0.is_none() {
if !expressions::expr(p) {
p.error("expected expression");
}
}
Expand Down
145 changes: 62 additions & 83 deletions crates/parser/src/grammar/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,19 @@ pub(super) enum StmtWithSemi {

const EXPR_FIRST: TokenSet = LHS_FIRST;

pub(super) fn expr(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
pub(super) fn expr(p: &mut Parser) -> bool {
let r = Restrictions { forbid_structs: false, prefer_stmt: false };
expr_bp(p, r, 1)
expr_bp(p, None, r, 1).is_some()
}

pub(super) fn expr_with_attrs(p: &mut Parser) -> bool {
let m = p.start();
let has_attrs = p.at(T![#]);
attributes::outer_attrs(p);

let (cm, _block_like) = expr(p);
let success = cm.is_some();

match (has_attrs, cm) {
(true, Some(cm)) => cm.extend_to(p, m),
_ => m.abandon(p),
}

success
}

pub(super) fn expr_stmt(p: &mut Parser) -> (Option<CompletedMarker>, BlockLike) {
pub(super) fn expr_stmt(p: &mut Parser, m: Option<Marker>) -> Option<(CompletedMarker, BlockLike)> {
let r = Restrictions { forbid_structs: false, prefer_stmt: true };
expr_bp(p, r, 1)
expr_bp(p, m, r, 1)
}

fn expr_no_struct(p: &mut Parser) {
let r = Restrictions { forbid_structs: true, prefer_stmt: false };
expr_bp(p, r, 1);
expr_bp(p, None, r, 1);
}

pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
Expand All @@ -53,7 +37,6 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
// #[C] #[D] {}
// #[D] return ();
// }
let has_attrs = p.at(T![#]);
attributes::outer_attrs(p);

if p.at(T![let]) {
Expand All @@ -68,61 +51,39 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
Err(m) => m,
};

let (cm, blocklike) = expr_stmt(p);
let kind = cm.as_ref().map(|cm| cm.kind()).unwrap_or(ERROR);

if has_attrs {
if matches!(kind, BIN_EXPR | RANGE_EXPR) {
// test_err attr_on_expr_not_allowed
if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
if !(p.at(T!['}']) || (prefer_expr && p.at(EOF))) {
// test no_semi_after_block
// fn foo() {
// #[A] 1 + 2;
// #[B] if true {};
// if true {}
// loop {}
// match () {}
// while true {}
// for _ in () {}
// {}
// {}
// macro_rules! test {
// () => {}
// }
// test!{}
// }
p.error(format!("attributes are not allowed on {:?}", kind));
}
}

if p.at(T!['}']) || (prefer_expr && p.at(EOF)) {
// test attr_on_last_expr_in_block
// fn foo() {
// { #[A] bar!()? }
// #[B] &()
// }
match cm {
Some(cm) => cm.extend_to(p, m),
None => m.abandon(p),
}
} else {
// test no_semi_after_block
// fn foo() {
// if true {}
// loop {}
// match () {}
// while true {}
// for _ in () {}
// {}
// {}
// macro_rules! test {
// () => {}
// }
// test!{}
// }

match with_semi {
StmtWithSemi::No => (),
StmtWithSemi::Optional => {
p.eat(T![;]);
}
StmtWithSemi::Yes => {
if blocklike.is_block() {
let m = cm.precede(p);
match with_semi {
StmtWithSemi::No => (),
StmtWithSemi::Optional => {
p.eat(T![;]);
} else {
p.expect(T![;]);
}
StmtWithSemi::Yes => {
if blocklike.is_block() {
p.eat(T![;]);
} else {
p.expect(T![;]);
}
}
}
}

m.complete(p, EXPR_STMT);
m.complete(p, EXPR_STMT);
}
}

// test let_stmt
Expand All @@ -138,7 +99,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi, prefer_expr: bool) {
if p.eat(T![=]) {
// test let_stmt_init
// fn f() { let x = 92; }
expressions::expr_with_attrs(p);
expressions::expr(p);
}

match with_semi {
Expand Down Expand Up @@ -234,20 +195,34 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) {
}

// Parses expression with binding power of at least bp.
fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMarker>, BlockLike) {
fn expr_bp(
p: &mut Parser,
m: Option<Marker>,
mut r: Restrictions,
bp: u8,
) -> Option<(CompletedMarker, BlockLike)> {
let m = m.unwrap_or_else(|| {
let m = p.start();
attributes::outer_attrs(p);
m
});
let mut lhs = match lhs(p, r) {
Some((lhs, blocklike)) => {
let lhs = lhs.extend_to(p, m);
if r.prefer_stmt && blocklike.is_block() {
// test stmt_bin_expr_ambiguity
// fn f() {
// let _ = {1} & 2;
// {1} &2;
// }
return (Some(lhs), BlockLike::Block);
return Some((lhs, BlockLike::Block));
}
lhs
}
None => return (None, BlockLike::NotBlock),
None => {
m.abandon(p);
return None;
}
};

loop {
Expand Down Expand Up @@ -285,10 +260,10 @@ fn expr_bp(p: &mut Parser, mut r: Restrictions, bp: u8) -> (Option<CompletedMark
}
}

expr_bp(p, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
}
(Some(lhs), BlockLike::NotBlock)
Some((lhs, BlockLike::NotBlock))
}

const LHS_FIRST: TokenSet =
Expand Down Expand Up @@ -341,9 +316,10 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
m = p.start();
p.bump(op);
if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
expr_bp(p, r, 2);
expr_bp(p, None, r, 2);
}
return Some((m.complete(p, RANGE_EXPR), BlockLike::NotBlock));
let cm = m.complete(p, RANGE_EXPR);
return Some((cm, BlockLike::NotBlock));
}
}

Expand All @@ -353,12 +329,15 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
// {p}.x = 10;
// }
let (lhs, blocklike) = atom::atom_expr(p, r)?;
return Some(postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block())));
let (cm, block_like) =
postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()));
return Some((cm, block_like));
}
};
// parse the interior of the unary expression
expr_bp(p, r, 255);
Some((m.complete(p, kind), BlockLike::NotBlock))
expr_bp(p, None, r, 255);
let cm = m.complete(p, kind);
Some((cm, BlockLike::NotBlock))
}

fn postfix_expr(
Expand Down Expand Up @@ -536,7 +515,7 @@ fn arg_list(p: &mut Parser) {
// fn main() {
// foo(#[attr] 92)
// }
if !expr_with_attrs(p) {
if !expr(p) {
break;
}
if !p.at(T![')']) && !p.expect(T![,]) {
Expand Down
19 changes: 11 additions & 8 deletions crates/parser/src/grammar/expressions/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker {

// test tuple_attrs
// const A: (i64, i64) = (1, #[cfg(test)] 2);
if !expr_with_attrs(p) {
if !expr(p) {
break;
}

Expand Down Expand Up @@ -209,7 +209,7 @@ fn array_expr(p: &mut Parser) -> CompletedMarker {

// test array_attrs
// const A: &[i64] = &[1, #[cfg(test)] 2];
if !expr_with_attrs(p) {
if !expr(p) {
break;
}

Expand Down Expand Up @@ -438,7 +438,10 @@ fn match_arm(p: &mut Parser) {
match_guard(p);
}
p.expect(T![=>]);
let blocklike = expr_stmt(p).1;
let blocklike = match expr_stmt(p, None) {
Some((_, blocklike)) => blocklike,
None => BlockLike::NotBlock,
};

// test match_arms_commas
// fn foo() {
Expand Down Expand Up @@ -619,14 +622,14 @@ fn meta_var_expr(p: &mut Parser) -> CompletedMarker {
assert!(p.at(L_DOLLAR));
let m = p.start();
p.bump(L_DOLLAR);
let (completed, _is_block) =
expr_bp(p, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);
let expr = expr_bp(p, None, Restrictions { forbid_structs: false, prefer_stmt: false }, 1);

match (completed, p.current()) {
(Some(it), R_DOLLAR) => {
match (expr, p.current()) {
(Some((cm, _)), R_DOLLAR) => {
p.bump(R_DOLLAR);
// FIXME: this leaves the dollar hanging in the air...
m.abandon(p);
it
cm
}
_ => {
while !p.at(R_DOLLAR) {
Expand Down
13 changes: 9 additions & 4 deletions crates/parser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,16 @@ impl CompletedMarker {
}

/// Extends this completed marker *to the left* up to `m`.
pub(crate) fn extend_to(self, p: &mut Parser, mut m: Marker) {
assert!(m.pos <= self.pos);
pub(crate) fn extend_to(self, p: &mut Parser, mut m: Marker) -> CompletedMarker {
m.bomb.defuse();

p.events.swap(self.pos as usize, m.pos as usize);
let idx = m.pos as usize;
match &mut p.events[idx] {
Event::Start { forward_parent, .. } => {
*forward_parent = Some(self.pos - m.pos);
}
_ => unreachable!(),
}
self
}

pub(crate) fn kind(&self) -> SyntaxKind {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ SOURCE_FILE@0..43
PATH_SEGMENT@23..24
NAME_REF@23..24
IDENT@23..24 "f"
EXPR_STMT@24..25
ERROR@24..25
COLON@24..25 ":"
ERROR@24..25
COLON@24..25 ":"
WHITESPACE@25..26 " "
PATH_EXPR@26..29
PATH@26..29
Expand All @@ -55,4 +54,3 @@ error 15..15: expected an item
error 17..17: expected an item
error 24..24: expected SEMICOLON
error 24..24: expected expression
error 25..25: expected SEMICOLON
Loading