rustc_ast/util/
parser.rs

1use rustc_span::kw;
2
3use crate::ast::{self, AssignOpKind, BinOpKind, RangeLimits};
4use crate::token::{self, Token};
5
6/// Associative operator.
7#[derive(Copy, Clone, PartialEq, Debug)]
8pub enum AssocOp {
9    /// A binary op.
10    Binary(BinOpKind),
11    /// `?=` where ? is one of the assignable BinOps
12    AssignOp(AssignOpKind),
13    /// `=`
14    Assign,
15    /// `as`
16    Cast,
17    /// `..` or `..=` range
18    Range(RangeLimits),
19}
20
21#[derive(PartialEq, Debug)]
22pub enum Fixity {
23    /// The operator is left-associative
24    Left,
25    /// The operator is right-associative
26    Right,
27    /// The operator is not associative
28    None,
29}
30
31impl AssocOp {
32    /// Creates a new AssocOp from a token.
33    pub fn from_token(t: &Token) -> Option<AssocOp> {
34        use AssocOp::*;
35        match t.kind {
36            token::Eq => Some(Assign),
37            token::Plus => Some(Binary(BinOpKind::Add)),
38            token::Minus => Some(Binary(BinOpKind::Sub)),
39            token::Star => Some(Binary(BinOpKind::Mul)),
40            token::Slash => Some(Binary(BinOpKind::Div)),
41            token::Percent => Some(Binary(BinOpKind::Rem)),
42            token::Caret => Some(Binary(BinOpKind::BitXor)),
43            token::And => Some(Binary(BinOpKind::BitAnd)),
44            token::Or => Some(Binary(BinOpKind::BitOr)),
45            token::Shl => Some(Binary(BinOpKind::Shl)),
46            token::Shr => Some(Binary(BinOpKind::Shr)),
47            token::PlusEq => Some(AssignOp(AssignOpKind::AddAssign)),
48            token::MinusEq => Some(AssignOp(AssignOpKind::SubAssign)),
49            token::StarEq => Some(AssignOp(AssignOpKind::MulAssign)),
50            token::SlashEq => Some(AssignOp(AssignOpKind::DivAssign)),
51            token::PercentEq => Some(AssignOp(AssignOpKind::RemAssign)),
52            token::CaretEq => Some(AssignOp(AssignOpKind::BitXorAssign)),
53            token::AndEq => Some(AssignOp(AssignOpKind::BitAndAssign)),
54            token::OrEq => Some(AssignOp(AssignOpKind::BitOrAssign)),
55            token::ShlEq => Some(AssignOp(AssignOpKind::ShlAssign)),
56            token::ShrEq => Some(AssignOp(AssignOpKind::ShrAssign)),
57            token::Lt => Some(Binary(BinOpKind::Lt)),
58            token::Le => Some(Binary(BinOpKind::Le)),
59            token::Ge => Some(Binary(BinOpKind::Ge)),
60            token::Gt => Some(Binary(BinOpKind::Gt)),
61            token::EqEq => Some(Binary(BinOpKind::Eq)),
62            token::Ne => Some(Binary(BinOpKind::Ne)),
63            token::AndAnd => Some(Binary(BinOpKind::And)),
64            token::OrOr => Some(Binary(BinOpKind::Or)),
65            token::DotDot => Some(Range(RangeLimits::HalfOpen)),
66            // DotDotDot is no longer supported, but we need some way to display the error
67            token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)),
68            // `<-` should probably be `< -`
69            token::LArrow => Some(Binary(BinOpKind::Lt)),
70            _ if t.is_keyword(kw::As) => Some(Cast),
71            _ => None,
72        }
73    }
74
75    /// Gets the precedence of this operator
76    pub fn precedence(&self) -> ExprPrecedence {
77        use AssocOp::*;
78        match *self {
79            Cast => ExprPrecedence::Cast,
80            Binary(bin_op) => bin_op.precedence(),
81            Range(_) => ExprPrecedence::Range,
82            Assign | AssignOp(_) => ExprPrecedence::Assign,
83        }
84    }
85
86    /// Gets the fixity of this operator
87    pub fn fixity(&self) -> Fixity {
88        use AssocOp::*;
89        // NOTE: it is a bug to have an operators that has same precedence but different fixities!
90        match *self {
91            Assign | AssignOp(_) => Fixity::Right,
92            Binary(binop) => binop.fixity(),
93            Cast => Fixity::Left,
94            Range(_) => Fixity::None,
95        }
96    }
97
98    pub fn is_comparison(&self) -> bool {
99        use AssocOp::*;
100        match *self {
101            Binary(binop) => binop.is_comparison(),
102            Assign | AssignOp(_) | Cast | Range(_) => false,
103        }
104    }
105
106    pub fn is_assign_like(&self) -> bool {
107        use AssocOp::*;
108        match *self {
109            Assign | AssignOp(_) => true,
110            Cast | Binary(_) | Range(_) => false,
111        }
112    }
113
114    /// This operator could be used to follow a block unambiguously.
115    ///
116    /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with
117    /// parentheses while having a high degree of confidence on the correctness of the suggestion.
118    pub fn can_continue_expr_unambiguously(&self) -> bool {
119        use AssocOp::*;
120        use BinOpKind::*;
121        matches!(
122            self,
123            Assign | // `{ 42 } = { 42 }`
124            Binary(
125                BitXor | // `{ 42 } ^ 3`
126                Div | // `{ 42 } / 42`
127                Rem | // `{ 42 } % 2`
128                Shr | // `{ 42 } >> 2`
129                Le | // `{ 42 } <= 3`
130                Gt | // `{ 42 } > 3`
131                Ge   // `{ 42 } >= 3`
132            ) |
133            AssignOp(_) | // `{ 42 } +=`
134            // Equal | // `{ 42 } == { 42 }`    Accepting these here would regress incorrect
135            // NotEqual | // `{ 42 } != { 42 }  struct literals parser recovery.
136            Cast // `{ 42 } as usize`
137        )
138    }
139}
140
141#[derive(Clone, Copy, PartialEq, PartialOrd)]
142pub enum ExprPrecedence {
143    // return, break, yield, closures
144    Jump,
145    // = += -= *= /= %= &= |= ^= <<= >>=
146    Assign,
147    // .. ..=
148    Range,
149    // ||
150    LOr,
151    // &&
152    LAnd,
153    // == != < > <= >=
154    Compare,
155    // |
156    BitOr,
157    // ^
158    BitXor,
159    // &
160    BitAnd,
161    // << >>
162    Shift,
163    // + -
164    Sum,
165    // * / %
166    Product,
167    // as
168    Cast,
169    // unary - * ! & &mut
170    Prefix,
171    // paths, loops, function calls, array indexing, field expressions, method calls
172    Unambiguous,
173}
174
175/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
176pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
177    ExprPrecedence::LAnd
178}
179
180/// Suppose we have `let _ = e` and the `order` of `e`.
181/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
182///
183/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
184/// Can we print this as `let _ = a OP b`?
185pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
186    order <= prec_let_scrutinee_needs_par()
187}
188
189/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
190/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
191/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
192pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
193    match &value.kind {
194        ast::ExprKind::Struct(..) => true,
195
196        ast::ExprKind::Assign(lhs, rhs, _)
197        | ast::ExprKind::AssignOp(_, lhs, rhs)
198        | ast::ExprKind::Binary(_, lhs, rhs) => {
199            // X { y: 1 } + X { y: 2 }
200            contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
201        }
202        ast::ExprKind::Await(x, _)
203        | ast::ExprKind::Unary(_, x)
204        | ast::ExprKind::Cast(x, _)
205        | ast::ExprKind::Type(x, _)
206        | ast::ExprKind::Field(x, _)
207        | ast::ExprKind::Index(x, _, _)
208        | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {
209            // &X { y: 1 }, X { y: 1 }.y
210            contains_exterior_struct_lit(x)
211        }
212
213        ast::ExprKind::MethodCall(box ast::MethodCall { receiver, .. }) => {
214            // X { y: 1 }.bar(...)
215            contains_exterior_struct_lit(receiver)
216        }
217
218        _ => false,
219    }
220}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy