Skip to main content

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(#[automatically_derived]
impl ::core::marker::Copy for AssocOp { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for AssocOp { }
#[automatically_derived]
impl ::core::clone::Clone for AssocOp {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<BinOpKind>;
        let _: ::core::clone::AssertParamIsClone<AssignOpKind>;
        let _: ::core::clone::AssertParamIsClone<RangeLimits>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for AssocOp { }
#[automatically_derived]
impl ::core::cmp::PartialEq for AssocOp {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
                ::core::intrinsics::discriminant_value(other) &&
            match (self, other) {
                (Self::Binary(__self_0), Self::Binary(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Self::AssignOp(__self_0), Self::AssignOp(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Self::Range(__self_0), Self::Range(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for AssocOp {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Binary(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Binary",
                    &__self_0),
            Self::AssignOp(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "AssignOp", &__self_0),
            Self::Assign => ::core::fmt::Formatter::write_str(f, "Assign"),
            Self::Cast => ::core::fmt::Formatter::write_str(f, "Cast"),
            Self::Range(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Range",
                    &__self_0),
        }
    }
}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(#[automatically_derived]
impl ::core::marker::StructuralPartialEq for Fixity { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Fixity {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::fmt::Debug for Fixity {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                Fixity::Left => "Left",
                Fixity::Right => "Right",
                Fixity::None => "None",
            })
    }
}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
115#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ExprPrecedence { }
#[automatically_derived]
impl ::core::clone::Clone for ExprPrecedence {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ExprPrecedence { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for ExprPrecedence { }
#[automatically_derived]
impl ::core::cmp::PartialEq for ExprPrecedence {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for ExprPrecedence {
    #[inline]
    fn partial_cmp(&self, other: &Self)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::cmp::PartialOrd::partial_cmp(&::core::intrinsics::discriminant_value(self),
            &::core::intrinsics::discriminant_value(other))
    }
}PartialOrd)]
116pub enum ExprPrecedence {
117    // return, break, yield, closures
118    Jump,
119    // = += -= *= /= %= &= |= ^= <<= >>=
120    Assign,
121    // .. ..=
122    Range,
123    // ||
124    LOr,
125    // &&
126    LAnd,
127    // == != < > <= >=
128    Compare,
129    // |
130    BitOr,
131    // ^
132    BitXor,
133    // &
134    BitAnd,
135    // << >>
136    Shift,
137    // + -
138    Sum,
139    // * / %
140    Product,
141    // as
142    Cast,
143    // unary - * ! & &mut
144    Prefix,
145    // paths, loops, function calls, array indexing, field expressions, method calls
146    Unambiguous,
147}
148
149/// In `let p = e`, operators with precedence `<=` this one requires parentheses in `e`.
150pub fn prec_let_scrutinee_needs_par() -> ExprPrecedence {
151    ExprPrecedence::LAnd
152}
153
154/// Suppose we have `let _ = e` and the `order` of `e`.
155/// Is the `order` such that `e` in `let _ = e` needs parentheses when it is on the RHS?
156///
157/// Conversely, suppose that we have `(let _ = a) OP b` and `order` is that of `OP`.
158/// Can we print this as `let _ = a OP b`?
159pub fn needs_par_as_let_scrutinee(order: ExprPrecedence) -> bool {
160    order <= prec_let_scrutinee_needs_par()
161}
162
163/// Expressions that syntactically contain an "exterior" struct literal i.e., not surrounded by any
164/// parens or other delimiters, e.g., `X { y: 1 }`, `X { y: 1 }.method()`, `foo == X { y: 1 }` and
165/// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not.
166pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
167    match &value.kind {
168        ast::ExprKind::Struct(..) => true,
169
170        ast::ExprKind::Assign(lhs, rhs, _)
171        | ast::ExprKind::AssignOp(_, lhs, rhs)
172        | ast::ExprKind::Binary(_, lhs, rhs) => {
173            // X { y: 1 } + X { y: 2 }
174            contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
175        }
176        ast::ExprKind::Await(x, _)
177        | ast::ExprKind::Unary(_, x)
178        | ast::ExprKind::Cast(x, _)
179        | ast::ExprKind::Type(x, _)
180        | ast::ExprKind::Field(x, _)
181        | ast::ExprKind::Index(x, _, _)
182        | ast::ExprKind::Match(x, _, ast::MatchKind::Postfix) => {
183            // &X { y: 1 }, X { y: 1 }.y
184            contains_exterior_struct_lit(x)
185        }
186
187        ast::ExprKind::MethodCall(ast::MethodCall { receiver, .. }) => {
188            // X { y: 1 }.bar(...)
189            contains_exterior_struct_lit(receiver)
190        }
191
192        _ => false,
193    }
194}