welly_parser/expr/
op.rs

1/// Represents the binding precedence of an operator.
2/// No left-`Precedence` is ever equal to a right-`Precedence`.
3#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
4pub struct Precedence(u8);
5
6impl Precedence {
7    pub const MIN: Self = Precedence(0);
8    pub const MAX: Self = Precedence(34);
9}
10
11/// Represents one of Welly's arithmetic operations. See also [`Operator`].
12///
13/// [`Operator`]: super::Operator
14#[derive(Debug, Copy, Clone, PartialEq)]
15pub enum Op {
16    /// `OK(x)?` is `x`; `ERR(x)?` returns `ERR(x)`.
17    Query,
18
19    /// `(-7) ** 2` is `49`.
20    Pow,
21
22    /// `~3` is `-4`.
23    BitNot,
24
25    /// `+3` is `3`.
26    Plus,
27
28    /// `-3` is `-3`.
29    Minus,
30
31    /// `&x` is borrowed.
32    Borrow,
33
34    /// `$x` is shared.
35    Share,
36
37    /// `*x` is a fresh copy of `x`.
38    Clone,
39
40    /// `-7 * 2` is `-14`.
41    Mul,
42
43    /// `-7 / 2` is `-4`.
44    Div,
45
46    /// `-7 % 2` is `1`.
47    Rem,
48
49    /// `3 + 5` is `8`.
50    Add,
51
52    /// `3 - 5` is `-2`.
53    Sub,
54
55    /// `-7 << 2` is `-28`.
56    SL,
57
58    /// `-7 >> 2` is `-2`.
59    ASR,
60
61    /// `-7 >>> 2` is `(1 << 62) - 2`.
62    LSR,
63
64    /// `3 & 5` is `1`.
65    BitAnd,
66
67    /// `3 ^ 5` is `6`.
68    BitXor,
69
70    /// `3 | 5` is `7`.
71    BitOr,
72
73    /// `x: t` - A value `x` cast to a type `t`.
74    Cast,
75
76    /// `0..3` means `0, 1, 2`.
77    Exclusive,
78
79    /// `0...3` means `0, 1, 2, 3`.
80    Inclusive,
81
82    /// `3 < 5` is true.
83    LT,
84
85    /// `5 > 3` is true.
86    GT,
87
88    /// `3 <= 5` is true.
89    LE,
90
91    /// `5 >= 3` is true.
92    GE,
93
94    /// `3 <> 5` is `true`.
95    LG,
96
97    /// `3 == 5` is `false`.
98    EQ,
99
100    /// `3 != 5` is `true`.
101    NE,
102
103    /// `item in collection` - Membership test.
104    ///
105    /// Also abused as part of `for item in collection { ... }`.
106    In,
107
108    /// `not false` is `true`.
109    BoolNot,
110
111    /// `false and true` is `false`.
112    BoolAnd,
113
114    /// `false or true` is `true`.
115    BoolOr,
116
117    /// Used when two expressions are juxtaposed. Always an error.
118    Missing,
119}
120
121impl Op {
122    /// Returns the left and right [`Precedence`] of `self`.
123    ///
124    /// Differences from Rust and Python:
125    /// - `x in low .. high and b` means `(x in (low .. high)) and b`.
126    ///   - In Rust, there is no `in`.
127    ///     `low .. high && b` means `low .. (high && b)`.
128    ///   - In Python, `:` is part of array subscription.
129    ///     `a[x in low : high and b]` means `a[(x in low) : (high and b)]`.
130    ///
131    /// Differences from C, Java and Javascript:
132    /// - `x & 1 == 0` means `(x & 1) == 0`.
133    ///   - In C, Java and Javascript it means `x & (1 == 0)`.
134    /// - `-x ** 2` means `-(x ** 2)`
135    ///   - In Javascript it means `(-x) ** 2`.
136    pub const fn precedence(self) -> (Option<Precedence>, Option<Precedence>) {
137        const fn p(n: u8) -> Option<Precedence> { Some(Precedence(n)) }
138        use Op::*;
139        match self {
140            Query => (p(34), None),
141            Pow => (p(32), p(33)),
142            BitNot | Plus | Minus | Borrow | Share | Clone => (None, p(30)),
143            Mul | Div | Rem => (p(29), p(28)),
144            Add | Sub => (p(27), p(26)),
145            SL | ASR | LSR => (p(24), p(25)),
146            BitAnd => (p(23), p(22)),
147            BitXor => (p(21), p(20)),
148            BitOr => (p(19), p(18)),
149            Cast => (p(16), p(17)),
150            Exclusive | Inclusive => (p(15), p(14)),
151            LT | GT | LE | GE | LG => (p(13), p(12)),
152            EQ | NE => (p(11), p(10)),
153            In => (p(9), p(8)),
154            BoolNot => (None, p(6)),
155            BoolAnd => (p(5), p(4)),
156            BoolOr => (p(3), p(2)),
157            Missing => (p(1), p(0)),
158        }
159    }
160}
161
162// ----------------------------------------------------------------------------
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[test]
169    fn limits() {
170        let (_, right) = Op::Missing.precedence();
171        assert_eq!(right.unwrap(), Precedence::MIN);
172        let (left, _) = Op::Query.precedence();
173        assert_eq!(left.unwrap(), Precedence::MAX);
174    }
175}