|
| 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