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