Skip to content

Commit 8d42439

Browse files
committed
Move precedence handling to crates/syntax
1 parent 2870b01 commit 8d42439

File tree

3 files changed

+117
-93
lines changed

3 files changed

+117
-93
lines changed

crates/ide-assists/src/handlers/remove_parentheses.rs

Lines changed: 1 addition & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
3030

3131
let expr = parens.expr()?;
3232
let parent = ast::Expr::cast(parens.syntax().parent()?);
33-
let is_ok_to_remove =
34-
parent.map_or(true, |p| ExprPrecedence::of(&expr) >= ExprPrecedence::of(&p));
33+
let is_ok_to_remove = expr.precedence() >= parent.as_ref().and_then(ast::Expr::precedence);
3534
if !is_ok_to_remove {
3635
return None;
3736
}
@@ -60,97 +59,6 @@ pub(crate) fn remove_parentheses(acc: &mut Assists, ctx: &AssistContext<'_>) ->
6059
)
6160
}
6261

63-
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
64-
pub enum ExprPrecedence {
65-
// N.B.: Order is important
66-
/// Precedence is unknown
67-
Dummy,
68-
Closure,
69-
Jump,
70-
Range,
71-
Bin(BinOpPresedence),
72-
Prefix,
73-
Postfix,
74-
Paren,
75-
}
76-
77-
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
78-
pub enum BinOpPresedence {
79-
// N.B.: Order is important
80-
/// `=`, `+=`, `-=`, `*=`, `/=`, `%=`, `|=`, `&=`
81-
Assign,
82-
/// `||`
83-
LOr,
84-
/// `&&`
85-
LAnd,
86-
/// `<`, `<=`, `>`, `>=`, `==` and `!=`
87-
Cmp,
88-
/// `|`
89-
BitOr,
90-
/// `^`
91-
BitXor,
92-
/// `&`
93-
BitAnd,
94-
/// `<<` and `>>`
95-
Shift,
96-
/// `+` and `-`
97-
Add,
98-
/// `*`, `/` and `%`
99-
Mul,
100-
/// `as`
101-
As,
102-
}
103-
104-
impl ExprPrecedence {
105-
pub fn of(expr: &ast::Expr) -> Self {
106-
// Copied from <https://github.com/rust-lang/rust/blob/b6852428a8ea9728369b64b9964cad8e258403d3/compiler/rustc_ast/src/util/parser.rs#L296>
107-
use ast::Expr::*;
108-
109-
match expr {
110-
ClosureExpr(_) => Self::Closure,
111-
112-
ContinueExpr(_) | ReturnExpr(_) | YieldExpr(_) | BreakExpr(_) => Self::Jump,
113-
114-
RangeExpr(_) => Self::Range,
115-
116-
BinExpr(bin_expr) => bin_expr
117-
.op_kind()
118-
.map(|op| match op {
119-
ast::BinaryOp::LogicOp(op) => match op {
120-
ast::LogicOp::And => BinOpPresedence::LAnd,
121-
ast::LogicOp::Or => BinOpPresedence::LOr,
122-
},
123-
ast::BinaryOp::ArithOp(op) => match op {
124-
ast::ArithOp::Add => BinOpPresedence::Add,
125-
ast::ArithOp::Mul => BinOpPresedence::Mul,
126-
ast::ArithOp::Sub => BinOpPresedence::Add,
127-
ast::ArithOp::Div => BinOpPresedence::Mul,
128-
ast::ArithOp::Rem => BinOpPresedence::Mul,
129-
ast::ArithOp::Shl => BinOpPresedence::Shift,
130-
ast::ArithOp::Shr => BinOpPresedence::Shift,
131-
ast::ArithOp::BitXor => BinOpPresedence::BitXor,
132-
ast::ArithOp::BitOr => BinOpPresedence::BitOr,
133-
ast::ArithOp::BitAnd => BinOpPresedence::BitAnd,
134-
},
135-
ast::BinaryOp::CmpOp(_) => BinOpPresedence::Cmp,
136-
ast::BinaryOp::Assignment { .. } => BinOpPresedence::Assign,
137-
})
138-
.map(Self::Bin)
139-
.unwrap_or(Self::Dummy),
140-
CastExpr(_) => Self::Bin(BinOpPresedence::As),
141-
142-
BoxExpr(_) | RefExpr(_) | LetExpr(_) | PrefixExpr(_) => Self::Prefix,
143-
144-
AwaitExpr(_) | CallExpr(_) | MethodCallExpr(_) | FieldExpr(_) | IndexExpr(_)
145-
| TryExpr(_) | MacroExpr(_) => Self::Postfix,
146-
147-
ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_) | IfExpr(_)
148-
| WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_) | BlockExpr(_)
149-
| RecordExpr(_) | UnderscoreExpr(_) => Self::Paren,
150-
}
151-
}
152-
}
153-
15462
#[cfg(test)]
15563
mod tests {
15664
use crate::tests::{check_assist, check_assist_not_applicable};

crates/syntax/src/ast.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod operators;
99
pub mod edit;
1010
pub mod edit_in_place;
1111
pub mod make;
12+
pub mod prec;
1213

1314
use std::marker::PhantomData;
1415

crates/syntax/src/ast/prec.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//! Precedence representation.
2+
3+
use crate::ast::{self, BinExpr, Expr};
4+
5+
/// Precedence of an expression.
6+
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
7+
pub enum ExprPrecedence {
8+
// N.B.: Order is important
9+
Closure,
10+
Jump,
11+
Range,
12+
Bin(BinOpPresedence),
13+
Prefix,
14+
Postfix,
15+
Paren,
16+
}
17+
18+
/// Precedence of a binary operator.
19+
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
20+
pub enum BinOpPresedence {
21+
// N.B.: Order is important
22+
/// `=`, `+=`, `-=`, `*=`, `/=`, `%=`, `|=`, `&=`
23+
Assign,
24+
/// `||`
25+
LOr,
26+
/// `&&`
27+
LAnd,
28+
/// `<`, `<=`, `>`, `>=`, `==` and `!=`
29+
Cmp,
30+
/// `|`
31+
BitOr,
32+
/// `^`
33+
BitXor,
34+
/// `&`
35+
BitAnd,
36+
/// `<<` and `>>`
37+
Shift,
38+
/// `+` and `-`
39+
Add,
40+
/// `*`, `/` and `%`
41+
Mul,
42+
/// `as`
43+
As,
44+
}
45+
46+
impl Expr {
47+
/// Returns precedence of this expression.
48+
/// Usefull to preserve semantics in assists.
49+
///
50+
/// Returns `None` if this is a [`BinExpr`] and its [`op_kind`] returns `None`.
51+
///
52+
/// [`op_kind`]: BinExpr::op_kind
53+
/// [`BinExpr`]: Expr::BinExpr
54+
pub fn precedence(&self) -> Option<ExprPrecedence> {
55+
// Copied from <https://github.com/rust-lang/rust/blob/b6852428a8ea9728369b64b9964cad8e258403d3/compiler/rustc_ast/src/util/parser.rs#L296>
56+
use Expr::*;
57+
58+
let prec = match self {
59+
ClosureExpr(_) => ExprPrecedence::Closure,
60+
61+
ContinueExpr(_) | ReturnExpr(_) | YieldExpr(_) | BreakExpr(_) => ExprPrecedence::Jump,
62+
63+
RangeExpr(_) => ExprPrecedence::Range,
64+
65+
BinExpr(bin_expr) => return bin_expr.precedence().map(ExprPrecedence::Bin),
66+
CastExpr(_) => ExprPrecedence::Bin(BinOpPresedence::As),
67+
68+
BoxExpr(_) | RefExpr(_) | LetExpr(_) | PrefixExpr(_) => ExprPrecedence::Prefix,
69+
70+
AwaitExpr(_) | CallExpr(_) | MethodCallExpr(_) | FieldExpr(_) | IndexExpr(_)
71+
| TryExpr(_) | MacroExpr(_) => ExprPrecedence::Postfix,
72+
73+
ArrayExpr(_) | TupleExpr(_) | Literal(_) | PathExpr(_) | ParenExpr(_) | IfExpr(_)
74+
| WhileExpr(_) | ForExpr(_) | LoopExpr(_) | MatchExpr(_) | BlockExpr(_)
75+
| RecordExpr(_) | UnderscoreExpr(_) => ExprPrecedence::Paren,
76+
};
77+
78+
Some(prec)
79+
}
80+
}
81+
82+
impl BinExpr {
83+
/// Returns precedence of this binary expression.
84+
/// Usefull to preserve semantics in assists.
85+
///
86+
/// Returns `None` if [`op_kind`] returns `None`.
87+
///
88+
/// [`op_kind`]: BinExpr::op_kind
89+
pub fn precedence(&self) -> Option<BinOpPresedence> {
90+
use ast::{ArithOp::*, BinaryOp::*, LogicOp::*};
91+
92+
let prec = match self.op_kind()? {
93+
LogicOp(op) => match op {
94+
And => BinOpPresedence::LAnd,
95+
Or => BinOpPresedence::LOr,
96+
},
97+
ArithOp(op) => match op {
98+
Add => BinOpPresedence::Add,
99+
Mul => BinOpPresedence::Mul,
100+
Sub => BinOpPresedence::Add,
101+
Div => BinOpPresedence::Mul,
102+
Rem => BinOpPresedence::Mul,
103+
Shl => BinOpPresedence::Shift,
104+
Shr => BinOpPresedence::Shift,
105+
BitXor => BinOpPresedence::BitXor,
106+
BitOr => BinOpPresedence::BitOr,
107+
BitAnd => BinOpPresedence::BitAnd,
108+
},
109+
CmpOp(_) => BinOpPresedence::Cmp,
110+
Assignment { .. } => BinOpPresedence::Assign,
111+
};
112+
113+
Some(prec)
114+
}
115+
}

0 commit comments

Comments
 (0)