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}