nu_protocol/ast/
operator.rs

1use super::{Expr, Expression};
2use crate::{ShellError, Span};
3use serde::{Deserialize, Serialize};
4use std::fmt;
5use strum_macros::{EnumIter, EnumMessage};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, EnumMessage)]
8pub enum Comparison {
9    #[strum(message = "Equal to")]
10    Equal,
11    #[strum(message = "Not equal to")]
12    NotEqual,
13    #[strum(message = "Less than")]
14    LessThan,
15    #[strum(message = "Greater than")]
16    GreaterThan,
17    #[strum(message = "Less than or equal to")]
18    LessThanOrEqual,
19    #[strum(message = "Greater than or equal to")]
20    GreaterThanOrEqual,
21    #[strum(message = "Contains regex match")]
22    RegexMatch,
23    #[strum(message = "Does not contain regex match")]
24    NotRegexMatch,
25    #[strum(message = "Is a member of (doesn't use regex)")]
26    In,
27    #[strum(message = "Is not a member of (doesn't use regex)")]
28    NotIn,
29    #[strum(message = "Contains a value of (doesn't use regex)")]
30    Has,
31    #[strum(message = "Does not contain a value of (doesn't use regex)")]
32    NotHas,
33    #[strum(message = "Starts with")]
34    StartsWith,
35    #[strum(message = "Ends with")]
36    EndsWith,
37}
38
39impl Comparison {
40    pub const fn as_str(&self) -> &'static str {
41        match self {
42            Self::Equal => "==",
43            Self::NotEqual => "!=",
44            Self::LessThan => "<",
45            Self::GreaterThan => ">",
46            Self::LessThanOrEqual => "<=",
47            Self::GreaterThanOrEqual => ">=",
48            Self::RegexMatch => "=~",
49            Self::NotRegexMatch => "!~",
50            Self::In => "in",
51            Self::NotIn => "not-in",
52            Self::Has => "has",
53            Self::NotHas => "not-has",
54            Self::StartsWith => "starts-with",
55            Self::EndsWith => "ends-with",
56        }
57    }
58}
59
60impl AsRef<str> for Comparison {
61    fn as_ref(&self) -> &str {
62        self.as_str()
63    }
64}
65
66impl fmt::Display for Comparison {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.write_str(self.as_str())
69    }
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, EnumMessage)]
73pub enum Math {
74    #[strum(message = "Add (Plus)")]
75    Add,
76    #[strum(message = "Subtract (Minus)")]
77    Subtract,
78    #[strum(message = "Multiply")]
79    Multiply,
80    #[strum(message = "Divide")]
81    Divide,
82    #[strum(message = "Floor division")]
83    FloorDivide,
84    #[strum(message = "Floor division remainder (Modulo)")]
85    Modulo,
86    #[strum(message = "Power of")]
87    Pow,
88    #[strum(message = "Concatenates two lists, two strings, or two binary values")]
89    Concatenate,
90}
91
92impl Math {
93    pub const fn as_str(&self) -> &'static str {
94        match self {
95            Self::Add => "+",
96            Self::Subtract => "-",
97            Self::Multiply => "*",
98            Self::Divide => "/",
99            Self::FloorDivide => "//",
100            Self::Modulo => "mod",
101            Self::Pow => "**",
102            Self::Concatenate => "++",
103        }
104    }
105}
106
107impl AsRef<str> for Math {
108    fn as_ref(&self) -> &str {
109        self.as_str()
110    }
111}
112
113impl fmt::Display for Math {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        f.write_str(self.as_str())
116    }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, EnumMessage)]
120pub enum Boolean {
121    #[strum(message = "Logical OR (short-circuiting)")]
122    Or,
123    #[strum(message = "Logical XOR")]
124    Xor,
125    #[strum(message = "Logical AND (short-circuiting)")]
126    And,
127}
128
129impl Boolean {
130    pub const fn as_str(&self) -> &'static str {
131        match self {
132            Self::Or => "or",
133            Self::Xor => "xor",
134            Self::And => "and",
135        }
136    }
137}
138
139impl AsRef<str> for Boolean {
140    fn as_ref(&self) -> &str {
141        self.as_str()
142    }
143}
144
145impl fmt::Display for Boolean {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        f.write_str(self.as_str())
148    }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, EnumMessage)]
152pub enum Bits {
153    #[strum(message = "Bitwise OR")]
154    BitOr,
155    #[strum(message = "Bitwise exclusive OR")]
156    BitXor,
157    #[strum(message = "Bitwise AND")]
158    BitAnd,
159    #[strum(message = "Bitwise shift left")]
160    ShiftLeft,
161    #[strum(message = "Bitwise shift right")]
162    ShiftRight,
163}
164
165impl AsRef<str> for Bits {
166    fn as_ref(&self) -> &str {
167        self.as_str()
168    }
169}
170
171impl Bits {
172    pub const fn as_str(&self) -> &'static str {
173        match self {
174            Self::BitOr => "bit-or",
175            Self::BitXor => "bit-xor",
176            Self::BitAnd => "bit-and",
177            Self::ShiftLeft => "bit-shl",
178            Self::ShiftRight => "bit-shr",
179        }
180    }
181}
182
183impl fmt::Display for Bits {
184    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185        f.write_str(self.as_str())
186    }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter, EnumMessage)]
190pub enum Assignment {
191    #[strum(message = "Assigns a value to a variable.")]
192    Assign,
193    #[strum(message = "Adds a value to a variable.")]
194    AddAssign,
195    #[strum(message = "Subtracts a value from a variable.")]
196    SubtractAssign,
197    #[strum(message = "Multiplies a variable by a value")]
198    MultiplyAssign,
199    #[strum(message = "Divides a variable by a value.")]
200    DivideAssign,
201    #[strum(message = "Concatenates a variable with a list, string or binary.")]
202    ConcatenateAssign,
203}
204
205impl AsRef<str> for Assignment {
206    fn as_ref(&self) -> &str {
207        self.as_str()
208    }
209}
210
211impl Assignment {
212    pub const fn as_str(&self) -> &'static str {
213        match self {
214            Self::Assign => "=",
215            Self::AddAssign => "+=",
216            Self::SubtractAssign => "-=",
217            Self::MultiplyAssign => "*=",
218            Self::DivideAssign => "/=",
219            Self::ConcatenateAssign => "++=",
220        }
221    }
222}
223
224impl fmt::Display for Assignment {
225    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226        f.write_str(self.as_str())
227    }
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
231pub enum Operator {
232    Comparison(Comparison),
233    Math(Math),
234    Boolean(Boolean),
235    Bits(Bits),
236    Assignment(Assignment),
237}
238
239impl Operator {
240    pub const fn as_str(&self) -> &'static str {
241        match self {
242            Self::Comparison(comparison) => comparison.as_str(),
243            Self::Math(math) => math.as_str(),
244            Self::Boolean(boolean) => boolean.as_str(),
245            Self::Bits(bits) => bits.as_str(),
246            Self::Assignment(assignment) => assignment.as_str(),
247        }
248    }
249
250    pub const fn precedence(&self) -> u8 {
251        match self {
252            Self::Math(Math::Pow) => 100,
253            Self::Math(Math::Multiply)
254            | Self::Math(Math::Divide)
255            | Self::Math(Math::Modulo)
256            | Self::Math(Math::FloorDivide) => 95,
257            Self::Math(Math::Add) | Self::Math(Math::Subtract) => 90,
258            Self::Bits(Bits::ShiftLeft) | Self::Bits(Bits::ShiftRight) => 85,
259            Self::Comparison(Comparison::NotRegexMatch)
260            | Self::Comparison(Comparison::RegexMatch)
261            | Self::Comparison(Comparison::StartsWith)
262            | Self::Comparison(Comparison::EndsWith)
263            | Self::Comparison(Comparison::LessThan)
264            | Self::Comparison(Comparison::LessThanOrEqual)
265            | Self::Comparison(Comparison::GreaterThan)
266            | Self::Comparison(Comparison::GreaterThanOrEqual)
267            | Self::Comparison(Comparison::Equal)
268            | Self::Comparison(Comparison::NotEqual)
269            | Self::Comparison(Comparison::In)
270            | Self::Comparison(Comparison::NotIn)
271            | Self::Comparison(Comparison::Has)
272            | Self::Comparison(Comparison::NotHas)
273            | Self::Math(Math::Concatenate) => 80,
274            Self::Bits(Bits::BitAnd) => 75,
275            Self::Bits(Bits::BitXor) => 70,
276            Self::Bits(Bits::BitOr) => 60,
277            Self::Boolean(Boolean::And) => 50,
278            Self::Boolean(Boolean::Xor) => 45,
279            Self::Boolean(Boolean::Or) => 40,
280            Self::Assignment(_) => 10,
281        }
282    }
283}
284
285impl fmt::Display for Operator {
286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287        f.write_str(self.as_str())
288    }
289}
290
291#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumIter)]
292pub enum RangeInclusion {
293    Inclusive,
294    RightExclusive,
295}
296
297#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
298pub struct RangeOperator {
299    pub inclusion: RangeInclusion,
300    pub span: Span,
301    pub next_op_span: Span,
302}
303
304impl fmt::Display for RangeOperator {
305    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306        match self.inclusion {
307            RangeInclusion::Inclusive => write!(f, ".."),
308            RangeInclusion::RightExclusive => write!(f, "..<"),
309        }
310    }
311}
312
313pub fn eval_operator(op: &Expression) -> Result<Operator, ShellError> {
314    match op {
315        Expression {
316            expr: Expr::Operator(operator),
317            ..
318        } => Ok(*operator),
319        Expression { span, expr, .. } => Err(ShellError::UnknownOperator {
320            op_token: format!("{expr:?}"),
321            span: *span,
322        }),
323    }
324}