diff options
Diffstat (limited to 'src/tools/rust-analyzer/crates/syntax')
6 files changed, 125 insertions, 51 deletions
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 4e2a70d6cd9..bbb8413cbc0 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -241,7 +241,7 @@ RecordFieldList = RecordField = Attr* Visibility? - Name ':' Type + Name ':' Type ('=' Expr)? TupleFieldList = '(' fields:(TupleField (',' TupleField)* ','?)? ')' diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index 291fc646e21..aedf810b794 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -710,52 +710,6 @@ impl ast::Fn { } } -impl Removable for ast::MatchArm { - fn remove(&self) { - if let Some(sibling) = self.syntax().prev_sibling_or_token() { - if sibling.kind() == SyntaxKind::WHITESPACE { - ted::remove(sibling); - } - } - if let Some(sibling) = self.syntax().next_sibling_or_token() { - if sibling.kind() == T![,] { - ted::remove(sibling); - } - } - ted::remove(self.syntax()); - } -} - -impl ast::MatchArmList { - pub fn add_arm(&self, arm: ast::MatchArm) { - normalize_ws_between_braces(self.syntax()); - let mut elements = Vec::new(); - let position = match self.arms().last() { - Some(last_arm) => { - if needs_comma(&last_arm) { - ted::append_child(last_arm.syntax(), make::token(SyntaxKind::COMMA)); - } - Position::after(last_arm.syntax().clone()) - } - None => match self.l_curly_token() { - Some(it) => Position::after(it), - None => Position::last_child_of(self.syntax()), - }, - }; - let indent = IndentLevel::from_node(self.syntax()) + 1; - elements.push(make::tokens::whitespace(&format!("\n{indent}")).into()); - elements.push(arm.syntax().clone().into()); - if needs_comma(&arm) { - ted::append_child(arm.syntax(), make::token(SyntaxKind::COMMA)); - } - ted::insert_all(position, elements); - - fn needs_comma(arm: &ast::MatchArm) -> bool { - arm.expr().is_some_and(|e| !e.is_block_like()) && arm.comma_token().is_none() - } - } -} - impl ast::LetStmt { pub fn set_ty(&self, ty: Option<ast::Type>) { match ty { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 69e2a9f9c1b..58c76a456ab 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1,4 +1,4 @@ -//! Generated by `cargo codegen grammar`, do not edit by hand. +//! Generated by `cargo xtask codegen grammar`, do not edit by hand. #![allow(non_snake_case)] use crate::{ @@ -1539,9 +1539,13 @@ impl ast::HasName for RecordField {} impl ast::HasVisibility for RecordField {} impl RecordField { #[inline] + pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } + #[inline] + pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs index 85d20c2bd8c..df2e9619db1 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/tokens.rs @@ -1,4 +1,4 @@ -//! Generated by `cargo codegen grammar`, do not edit by hand. +//! Generated by `cargo xtask codegen grammar`, do not edit by hand. use crate::{ ast::AstToken, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index ff027ac5848..9dc2d832530 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -837,7 +837,8 @@ pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard { pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList { let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| { - let needs_comma = arm.expr().is_none_or(|it| !it.is_block_like()); + let needs_comma = + arm.comma_token().is_none() && arm.expr().is_none_or(|it| !it.is_block_like()); let comma = if needs_comma { "," } else { "" }; let arm = arm.syntax(); format_to_acc!(acc, " {arm}{comma}\n") diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs index 28089ffb377..5d33f132ac1 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/prec.rs @@ -5,7 +5,122 @@ use crate::{ match_ast, AstNode, SyntaxNode, }; +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] +pub enum ExprPrecedence { + // return, break, yield, closures + Jump, + // = += -= *= /= %= &= |= ^= <<= >>= + Assign, + // .. ..= + Range, + // || + LOr, + // && + LAnd, + // == != < > <= >= + Compare, + // | + BitOr, + // ^ + BitXor, + // & + BitAnd, + // << >> + Shift, + // + - + Sum, + // * / % + Product, + // as + Cast, + // unary - * ! & &mut + Prefix, + // paths, loops, function calls, array indexing, field expressions, method calls + Unambiguous, +} + +#[derive(PartialEq, Debug)] +pub enum Fixity { + /// The operator is left-associative + Left, + /// The operator is right-associative + Right, + /// The operator is not associative + None, +} + +pub fn precedence(expr: &ast::Expr) -> ExprPrecedence { + match expr { + Expr::ClosureExpr(closure) => match closure.ret_type() { + None => ExprPrecedence::Jump, + Some(_) => ExprPrecedence::Unambiguous, + }, + + Expr::BreakExpr(_) + | Expr::ContinueExpr(_) + | Expr::ReturnExpr(_) + | Expr::YeetExpr(_) + | Expr::YieldExpr(_) => ExprPrecedence::Jump, + + Expr::RangeExpr(..) => ExprPrecedence::Range, + + Expr::BinExpr(bin_expr) => match bin_expr.op_kind() { + Some(it) => match it { + BinaryOp::LogicOp(logic_op) => match logic_op { + ast::LogicOp::And => ExprPrecedence::LAnd, + ast::LogicOp::Or => ExprPrecedence::LOr, + }, + BinaryOp::ArithOp(arith_op) => match arith_op { + ast::ArithOp::Add | ast::ArithOp::Sub => ExprPrecedence::Sum, + ast::ArithOp::Div | ast::ArithOp::Rem | ast::ArithOp::Mul => { + ExprPrecedence::Product + } + ast::ArithOp::Shl | ast::ArithOp::Shr => ExprPrecedence::Shift, + ast::ArithOp::BitXor => ExprPrecedence::BitXor, + ast::ArithOp::BitOr => ExprPrecedence::BitOr, + ast::ArithOp::BitAnd => ExprPrecedence::BitAnd, + }, + BinaryOp::CmpOp(_) => ExprPrecedence::Compare, + BinaryOp::Assignment { .. } => ExprPrecedence::Assign, + }, + None => ExprPrecedence::Unambiguous, + }, + Expr::CastExpr(_) => ExprPrecedence::Cast, + + Expr::LetExpr(_) | Expr::PrefixExpr(_) | Expr::RefExpr(_) => ExprPrecedence::Prefix, + + Expr::ArrayExpr(_) + | Expr::AsmExpr(_) + | Expr::AwaitExpr(_) + | Expr::BecomeExpr(_) + | Expr::BlockExpr(_) + | Expr::CallExpr(_) + | Expr::FieldExpr(_) + | Expr::ForExpr(_) + | Expr::FormatArgsExpr(_) + | Expr::IfExpr(_) + | Expr::IndexExpr(_) + | Expr::Literal(_) + | Expr::LoopExpr(_) + | Expr::MacroExpr(_) + | Expr::MatchExpr(_) + | Expr::MethodCallExpr(_) + | Expr::OffsetOfExpr(_) + | Expr::ParenExpr(_) + | Expr::PathExpr(_) + | Expr::RecordExpr(_) + | Expr::TryExpr(_) + | Expr::TupleExpr(_) + | Expr::UnderscoreExpr(_) + | Expr::WhileExpr(_) => ExprPrecedence::Unambiguous, + } +} + impl Expr { + pub fn precedence(&self) -> ExprPrecedence { + precedence(self) + } + // Implementation is based on // - https://doc.rust-lang.org/reference/expressions.html#expression-precedence // - https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html @@ -261,7 +376,7 @@ impl Expr { } /// Returns true if self is one of `return`, `break`, `continue` or `yield` with **no associated value**. - fn is_ret_like_with_no_value(&self) -> bool { + pub fn is_ret_like_with_no_value(&self) -> bool { use Expr::*; match self { |
