Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow post-fix match to parse #16925

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions crates/parser/src/grammar/expressions.rs
Expand Up @@ -2,6 +2,8 @@ mod atom;

use crate::grammar::attributes::ATTRIBUTE_FIRST;

use self::atom::match_expr;

use super::*;

pub(crate) use atom::{block_expr, match_arm_list};
Expand Down Expand Up @@ -470,6 +472,15 @@ fn postfix_dot_expr<const FLOAT_RECOVERY: bool>(
return Ok(m.complete(p, AWAIT_EXPR));
}

// Post-fix match
if p.nth(nth1) == T![match] {
if !FLOAT_RECOVERY {
p.bump(T![.]);
}
let m = lhs.precede(p);
return Ok(match_expr(p, Some(m)));
}

if p.at(T![..=]) || p.at(T![..]) {
return Err(lhs);
}
Expand Down
28 changes: 21 additions & 7 deletions crates/parser/src/grammar/expressions/atom.rs
Expand Up @@ -101,7 +101,7 @@ pub(super) fn atom_expr(
T![loop] => loop_expr(p, None),
T![while] => while_expr(p, None),
T![try] => try_block_expr(p, None),
T![match] => match_expr(p),
T![match] => match_expr(p, None),
T![return] => return_expr(p),
T![become] => become_expr(p),
T![yield] => yield_expr(p),
Expand Down Expand Up @@ -476,16 +476,30 @@ fn let_expr(p: &mut Parser<'_>) -> CompletedMarker {
// match S {};
// match { } { _ => () };
// match { S {} } {};
//
// S.match { _ => () };
// S.match { }.match { };
// 1.match { };
// x.0.match { };
// x.0().match { }?.hello();
// x.0.0.match { };
// x.0. match { };
// }
fn match_expr(p: &mut Parser<'_>) -> CompletedMarker {
assert!(p.at(T![match]));
let m = p.start();
p.bump(T![match]);
expr_no_struct(p);
pub(crate) fn match_expr(p: &mut Parser<'_>, postfix: Option<Marker>) -> CompletedMarker {
let m;
if let Some(mark) = postfix {
m = mark;
p.bump(T![match]);
} else {
m = p.start();
p.bump(T![match]);
expr_no_struct(p);
}

if p.at(T!['{']) {
match_arm_list(p);
} else {
p.error("expected `{`");
p.error(format!("expected `{{`, found {:?}", p.current()));
}
m.complete(p, MATCH_EXPR)
}
Expand Down
161 changes: 161 additions & 0 deletions crates/parser/test_data/parser/inline/ok/0071_match_expr.rast
Expand Up @@ -91,6 +91,167 @@ SOURCE_FILE
L_CURLY "{"
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n\n "
EXPR_STMT
MATCH_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "S"
DOT "."
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
MATCH_ARM
WILDCARD_PAT
UNDERSCORE "_"
WHITESPACE " "
FAT_ARROW "=>"
WHITESPACE " "
TUPLE_EXPR
L_PAREN "("
R_PAREN ")"
WHITESPACE " "
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
MATCH_EXPR
MATCH_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "S"
DOT "."
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
R_CURLY "}"
DOT "."
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
MATCH_EXPR
LITERAL
INT_NUMBER "1"
DOT "."
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
MATCH_EXPR
FIELD_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "x"
DOT "."
NAME_REF
INT_NUMBER "0"
DOT "."
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
METHOD_CALL_EXPR
TRY_EXPR
MATCH_EXPR
CALL_EXPR
FIELD_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "x"
DOT "."
NAME_REF
INT_NUMBER "0"
ARG_LIST
L_PAREN "("
R_PAREN ")"
DOT "."
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
R_CURLY "}"
QUESTION "?"
DOT "."
NAME_REF
IDENT "hello"
ARG_LIST
L_PAREN "("
R_PAREN ")"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
MATCH_EXPR
FIELD_EXPR
FIELD_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "x"
DOT "."
NAME_REF
INT_NUMBER "0"
DOT "."
NAME_REF
INT_NUMBER "0"
DOT "."
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n "
EXPR_STMT
MATCH_EXPR
FIELD_EXPR
PATH_EXPR
PATH
PATH_SEGMENT
NAME_REF
IDENT "x"
DOT "."
NAME_REF
INT_NUMBER "0"
DOT "."
WHITESPACE " "
MATCH_KW "match"
WHITESPACE " "
MATCH_ARM_LIST
L_CURLY "{"
WHITESPACE " "
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n"
R_CURLY "}"
WHITESPACE "\n"
8 changes: 8 additions & 0 deletions crates/parser/test_data/parser/inline/ok/0071_match_expr.rs
Expand Up @@ -3,4 +3,12 @@ fn foo() {
match S {};
match { } { _ => () };
match { S {} } {};

S.match { _ => () };
S.match { }.match { };
1.match { };
x.0.match { };
x.0().match { }?.hello();
x.0.0.match { };
x.0. match { };
}
2 changes: 1 addition & 1 deletion crates/syntax/rust.ungram
Expand Up @@ -512,7 +512,7 @@ RangeExpr =
Attr* start:Expr? op:('..' | '..=') end:Expr?

MatchExpr =
Attr* 'match' Expr MatchArmList
Attr* 'match' Expr MatchArmList | Attr* Expr '.' 'match' MatchArmList

MatchArmList =
'{'
Expand Down
1 change: 1 addition & 0 deletions crates/syntax/src/ast/generated/nodes.rs
Expand Up @@ -759,6 +759,7 @@ impl ast::HasAttrs for MatchExpr {}
impl MatchExpr {
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
pub fn match_arm_list(&self) -> Option<MatchArmList> { support::child(&self.syntax) }
pub fn dot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![.]) }
pub fn match_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![match]) }
}

Expand Down