mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 13:48:50 +00:00
Parse let
expressions in order to support let
chains
We still need to reject freestanding `let` expressions: see https://github.com/rust-analyzer/rust-analyzer/issues/11320#issuecomment-1018212465.
This commit is contained in:
parent
d6ed146a1c
commit
de8633f15f
7 changed files with 99 additions and 67 deletions
|
@ -29,6 +29,15 @@ fn expr_no_struct(p: &mut Parser) {
|
||||||
expr_bp(p, None, r, 1);
|
expr_bp(p, None, r, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses the expression in `let pattern = expression`.
|
||||||
|
/// It needs to be parsed with lower precedence than `&&`, so that
|
||||||
|
/// `if let true = true && false` is parsed as `if (let true = true) && (true)`
|
||||||
|
/// and not `if let true = (true && true)`.
|
||||||
|
fn expr_let(p: &mut Parser) {
|
||||||
|
let r = Restrictions { forbid_structs: true, prefer_stmt: false };
|
||||||
|
expr_bp(p, None, r, 5);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn stmt(p: &mut Parser, semicolon: Semicolon) {
|
pub(super) fn stmt(p: &mut Parser, semicolon: Semicolon) {
|
||||||
if p.eat(T![;]) {
|
if p.eat(T![;]) {
|
||||||
return;
|
return;
|
||||||
|
@ -185,6 +194,7 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) {
|
||||||
T![%] if p.at(T![%=]) => (1, T![%=]),
|
T![%] if p.at(T![%=]) => (1, T![%=]),
|
||||||
T![%] => (11, T![%]),
|
T![%] => (11, T![%]),
|
||||||
T![&] if p.at(T![&=]) => (1, T![&=]),
|
T![&] if p.at(T![&=]) => (1, T![&=]),
|
||||||
|
// If you update this, remember to update `expr_let()` too.
|
||||||
T![&] if p.at(T![&&]) => (4, T![&&]),
|
T![&] if p.at(T![&&]) => (4, T![&&]),
|
||||||
T![&] => (8, T![&]),
|
T![&] => (8, T![&]),
|
||||||
T![/] if p.at(T![/=]) => (1, T![/=]),
|
T![/] if p.at(T![/=]) => (1, T![/=]),
|
||||||
|
|
|
@ -79,6 +79,7 @@ pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<(CompletedMar
|
||||||
closure_expr(p)
|
closure_expr(p)
|
||||||
}
|
}
|
||||||
T![if] => if_expr(p),
|
T![if] => if_expr(p),
|
||||||
|
T![let] => let_expr(p),
|
||||||
|
|
||||||
T![loop] => loop_expr(p, None),
|
T![loop] => loop_expr(p, None),
|
||||||
T![box] => box_expr(p, None),
|
T![box] => box_expr(p, None),
|
||||||
|
@ -286,7 +287,7 @@ fn if_expr(p: &mut Parser) -> CompletedMarker {
|
||||||
assert!(p.at(T![if]));
|
assert!(p.at(T![if]));
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
p.bump(T![if]);
|
p.bump(T![if]);
|
||||||
condition(p);
|
expr_no_struct(p);
|
||||||
block_expr(p);
|
block_expr(p);
|
||||||
if p.at(T![else]) {
|
if p.at(T![else]) {
|
||||||
p.bump(T![else]);
|
p.bump(T![else]);
|
||||||
|
@ -335,7 +336,7 @@ fn while_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
|
||||||
assert!(p.at(T![while]));
|
assert!(p.at(T![while]));
|
||||||
let m = m.unwrap_or_else(|| p.start());
|
let m = m.unwrap_or_else(|| p.start());
|
||||||
p.bump(T![while]);
|
p.bump(T![while]);
|
||||||
condition(p);
|
expr_no_struct(p);
|
||||||
block_expr(p);
|
block_expr(p);
|
||||||
m.complete(p, WHILE_EXPR)
|
m.complete(p, WHILE_EXPR)
|
||||||
}
|
}
|
||||||
|
@ -355,22 +356,18 @@ fn for_expr(p: &mut Parser, m: Option<Marker>) -> CompletedMarker {
|
||||||
m.complete(p, FOR_EXPR)
|
m.complete(p, FOR_EXPR)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test cond
|
// test let_expr
|
||||||
// fn foo() { if let Some(_) = None {} }
|
// fn foo() {
|
||||||
// fn bar() {
|
// if let Some(_) = None && true {}
|
||||||
// if let Some(_) | Some(_) = None {}
|
// while 1 == 5 && (let None = None) {}
|
||||||
// if let | Some(_) = None {}
|
|
||||||
// while let Some(_) | Some(_) = None {}
|
|
||||||
// while let | Some(_) = None {}
|
|
||||||
// }
|
// }
|
||||||
fn condition(p: &mut Parser) {
|
fn let_expr(p: &mut Parser) -> CompletedMarker {
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
if p.eat(T![let]) {
|
p.bump(T![let]);
|
||||||
patterns::pattern_top(p);
|
patterns::pattern_top(p);
|
||||||
p.expect(T![=]);
|
p.expect(T![=]);
|
||||||
}
|
expr_let(p);
|
||||||
expr_no_struct(p);
|
m.complete(p, LET_EXPR)
|
||||||
m.complete(p, CONDITION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test match_expr
|
// test match_expr
|
||||||
|
@ -482,10 +479,6 @@ fn match_guard(p: &mut Parser) -> CompletedMarker {
|
||||||
assert!(p.at(T![if]));
|
assert!(p.at(T![if]));
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
p.bump(T![if]);
|
p.bump(T![if]);
|
||||||
if p.eat(T![let]) {
|
|
||||||
patterns::pattern_top(p);
|
|
||||||
p.expect(T![=]);
|
|
||||||
}
|
|
||||||
expr(p);
|
expr(p);
|
||||||
m.complete(p, MATCH_GUARD)
|
m.complete(p, MATCH_GUARD)
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,6 @@ pub enum SyntaxKind {
|
||||||
CLOSURE_EXPR,
|
CLOSURE_EXPR,
|
||||||
IF_EXPR,
|
IF_EXPR,
|
||||||
WHILE_EXPR,
|
WHILE_EXPR,
|
||||||
CONDITION,
|
|
||||||
LOOP_EXPR,
|
LOOP_EXPR,
|
||||||
FOR_EXPR,
|
FOR_EXPR,
|
||||||
CONTINUE_EXPR,
|
CONTINUE_EXPR,
|
||||||
|
@ -188,6 +187,7 @@ pub enum SyntaxKind {
|
||||||
STMT_LIST,
|
STMT_LIST,
|
||||||
RETURN_EXPR,
|
RETURN_EXPR,
|
||||||
YIELD_EXPR,
|
YIELD_EXPR,
|
||||||
|
LET_EXPR,
|
||||||
MATCH_EXPR,
|
MATCH_EXPR,
|
||||||
MATCH_ARM_LIST,
|
MATCH_ARM_LIST,
|
||||||
MATCH_ARM,
|
MATCH_ARM,
|
||||||
|
|
|
@ -884,7 +884,7 @@ pub struct IfExpr {
|
||||||
impl ast::HasAttrs for IfExpr {}
|
impl ast::HasAttrs for IfExpr {}
|
||||||
impl IfExpr {
|
impl IfExpr {
|
||||||
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
||||||
pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
|
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
|
pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,7 +1038,7 @@ impl ast::HasAttrs for WhileExpr {}
|
||||||
impl ast::HasLoopBody for WhileExpr {}
|
impl ast::HasLoopBody for WhileExpr {}
|
||||||
impl WhileExpr {
|
impl WhileExpr {
|
||||||
pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
|
pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
|
||||||
pub fn condition(&self) -> Option<Condition> { support::child(&self.syntax) }
|
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -1051,6 +1051,18 @@ impl YieldExpr {
|
||||||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct LetExpr {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl ast::HasAttrs for LetExpr {}
|
||||||
|
impl LetExpr {
|
||||||
|
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
|
||||||
|
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
|
||||||
|
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
||||||
|
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtList {
|
pub struct StmtList {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
@ -1106,17 +1118,6 @@ impl ArgList {
|
||||||
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Condition {
|
|
||||||
pub(crate) syntax: SyntaxNode,
|
|
||||||
}
|
|
||||||
impl Condition {
|
|
||||||
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
|
|
||||||
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
|
|
||||||
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
|
||||||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct MatchArmList {
|
pub struct MatchArmList {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
@ -1147,10 +1148,7 @@ pub struct MatchGuard {
|
||||||
}
|
}
|
||||||
impl MatchGuard {
|
impl MatchGuard {
|
||||||
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
|
||||||
pub fn let_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![let]) }
|
pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
|
|
||||||
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
|
||||||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -1524,6 +1522,7 @@ pub enum Expr {
|
||||||
TupleExpr(TupleExpr),
|
TupleExpr(TupleExpr),
|
||||||
WhileExpr(WhileExpr),
|
WhileExpr(WhileExpr),
|
||||||
YieldExpr(YieldExpr),
|
YieldExpr(YieldExpr),
|
||||||
|
LetExpr(LetExpr),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -2664,6 +2663,17 @@ impl AstNode for YieldExpr {
|
||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for LetExpr {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == LET_EXPR }
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for StmtList {
|
impl AstNode for StmtList {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
@ -2719,17 +2729,6 @@ impl AstNode for ArgList {
|
||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
impl AstNode for Condition {
|
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == CONDITION }
|
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
|
||||||
if Self::can_cast(syntax.kind()) {
|
|
||||||
Some(Self { syntax })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
|
||||||
}
|
|
||||||
impl AstNode for MatchArmList {
|
impl AstNode for MatchArmList {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == MATCH_ARM_LIST }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
@ -3336,6 +3335,9 @@ impl From<WhileExpr> for Expr {
|
||||||
impl From<YieldExpr> for Expr {
|
impl From<YieldExpr> for Expr {
|
||||||
fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) }
|
fn from(node: YieldExpr) -> Expr { Expr::YieldExpr(node) }
|
||||||
}
|
}
|
||||||
|
impl From<LetExpr> for Expr {
|
||||||
|
fn from(node: LetExpr) -> Expr { Expr::LetExpr(node) }
|
||||||
|
}
|
||||||
impl AstNode for Expr {
|
impl AstNode for Expr {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool {
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
match kind {
|
match kind {
|
||||||
|
@ -3344,7 +3346,7 @@ impl AstNode for Expr {
|
||||||
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS | MATCH_EXPR
|
| INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_CALL | MACRO_STMTS | MATCH_EXPR
|
||||||
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
|
| METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR
|
||||||
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
|
| RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR
|
||||||
| YIELD_EXPR => true,
|
| YIELD_EXPR | LET_EXPR => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3381,6 +3383,7 @@ impl AstNode for Expr {
|
||||||
TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
|
TUPLE_EXPR => Expr::TupleExpr(TupleExpr { syntax }),
|
||||||
WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
|
WHILE_EXPR => Expr::WhileExpr(WhileExpr { syntax }),
|
||||||
YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
|
YIELD_EXPR => Expr::YieldExpr(YieldExpr { syntax }),
|
||||||
|
LET_EXPR => Expr::LetExpr(LetExpr { syntax }),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(res)
|
Some(res)
|
||||||
|
@ -3418,6 +3421,7 @@ impl AstNode for Expr {
|
||||||
Expr::TupleExpr(it) => &it.syntax,
|
Expr::TupleExpr(it) => &it.syntax,
|
||||||
Expr::WhileExpr(it) => &it.syntax,
|
Expr::WhileExpr(it) => &it.syntax,
|
||||||
Expr::YieldExpr(it) => &it.syntax,
|
Expr::YieldExpr(it) => &it.syntax,
|
||||||
|
Expr::LetExpr(it) => &it.syntax,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3883,6 +3887,7 @@ impl AstNode for AnyHasAttrs {
|
||||||
| TUPLE_EXPR
|
| TUPLE_EXPR
|
||||||
| WHILE_EXPR
|
| WHILE_EXPR
|
||||||
| YIELD_EXPR
|
| YIELD_EXPR
|
||||||
|
| LET_EXPR
|
||||||
| STMT_LIST
|
| STMT_LIST
|
||||||
| RECORD_EXPR_FIELD_LIST
|
| RECORD_EXPR_FIELD_LIST
|
||||||
| RECORD_EXPR_FIELD
|
| RECORD_EXPR_FIELD
|
||||||
|
@ -4537,6 +4542,11 @@ impl std::fmt::Display for YieldExpr {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for LetExpr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for StmtList {
|
impl std::fmt::Display for StmtList {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
@ -4562,11 +4572,6 @@ impl std::fmt::Display for ArgList {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for Condition {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl std::fmt::Display for MatchArmList {
|
impl std::fmt::Display for MatchArmList {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
|
|
@ -397,7 +397,7 @@ pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Ex
|
||||||
expr_from_text(&format!("match {} {}", expr, match_arm_list))
|
expr_from_text(&format!("match {} {}", expr, match_arm_list))
|
||||||
}
|
}
|
||||||
pub fn expr_if(
|
pub fn expr_if(
|
||||||
condition: ast::Condition,
|
condition: ast::Expr,
|
||||||
then_branch: ast::BlockExpr,
|
then_branch: ast::BlockExpr,
|
||||||
else_branch: Option<ast::ElseBranch>,
|
else_branch: Option<ast::ElseBranch>,
|
||||||
) -> ast::Expr {
|
) -> ast::Expr {
|
||||||
|
@ -456,14 +456,8 @@ pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
|
||||||
fn expr_from_text(text: &str) -> ast::Expr {
|
fn expr_from_text(text: &str) -> ast::Expr {
|
||||||
ast_from_text(&format!("const C: () = {};", text))
|
ast_from_text(&format!("const C: () = {};", text))
|
||||||
}
|
}
|
||||||
|
pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
|
||||||
pub fn condition(expr: ast::Expr, pattern: Option<ast::Pat>) -> ast::Condition {
|
|
||||||
match pattern {
|
|
||||||
None => ast_from_text(&format!("const _: () = while {} {{}};", expr)),
|
|
||||||
Some(pattern) => {
|
|
||||||
ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
|
ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
|
pub fn arg_list(args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList {
|
||||||
|
|
|
@ -528,9 +528,39 @@ impl ast::Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::Condition {
|
impl ast::Expr {
|
||||||
|
/// Returns the `let` only if there is exactly one (that is, `let pat = expr`
|
||||||
|
/// or `((let pat = expr))`, but not `let pat = expr && expr` or `non_let_expr`).
|
||||||
|
pub fn single_let(&self) -> Option<ast::LetExpr> {
|
||||||
|
return get_pat(self.clone());
|
||||||
|
|
||||||
|
fn get_pat(expr: ast::Expr) -> Option<ast::LetExpr> {
|
||||||
|
match expr {
|
||||||
|
ast::Expr::ParenExpr(expr) => expr.expr().and_then(get_pat),
|
||||||
|
ast::Expr::LetExpr(expr) => Some(expr),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_pattern_cond(&self) -> bool {
|
pub fn is_pattern_cond(&self) -> bool {
|
||||||
self.let_token().is_some()
|
return contains_let(self.clone());
|
||||||
|
|
||||||
|
fn contains_let(expr: ast::Expr) -> bool {
|
||||||
|
match expr {
|
||||||
|
ast::Expr::BinExpr(expr)
|
||||||
|
if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) =>
|
||||||
|
{
|
||||||
|
expr.lhs()
|
||||||
|
.map(contains_let)
|
||||||
|
.or_else(|| expr.rhs().map(contains_let))
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
ast::Expr::ParenExpr(expr) => expr.expr().map_or(false, contains_let),
|
||||||
|
ast::Expr::LetExpr(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
"CLOSURE_EXPR",
|
"CLOSURE_EXPR",
|
||||||
"IF_EXPR",
|
"IF_EXPR",
|
||||||
"WHILE_EXPR",
|
"WHILE_EXPR",
|
||||||
"CONDITION",
|
|
||||||
"LOOP_EXPR",
|
"LOOP_EXPR",
|
||||||
"FOR_EXPR",
|
"FOR_EXPR",
|
||||||
"CONTINUE_EXPR",
|
"CONTINUE_EXPR",
|
||||||
|
@ -143,6 +142,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
|
||||||
"STMT_LIST",
|
"STMT_LIST",
|
||||||
"RETURN_EXPR",
|
"RETURN_EXPR",
|
||||||
"YIELD_EXPR",
|
"YIELD_EXPR",
|
||||||
|
"LET_EXPR",
|
||||||
"MATCH_EXPR",
|
"MATCH_EXPR",
|
||||||
"MATCH_ARM_LIST",
|
"MATCH_ARM_LIST",
|
||||||
"MATCH_ARM",
|
"MATCH_ARM",
|
||||||
|
|
Loading…
Reference in a new issue